[Sql] Как получить возвращаемое значение хранимой процедуры


Answers

Кроме того, чтобы получить результат (или любой другой выходной параметр, если на то пошло) из ADO.NET, вы должны сначала пропустить все возвращаемые результирующие наборы (или пропустить их с помощью NextResult)

Это означает, что если у вас есть такая процедура, как:

CREATE PROC Test(@x INT OUT) AS
    SELECT * From TestTable
    SELECT @x = 1

И постарайтесь сделать это:

SqlCommand cmd = connection.CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "Test"
cmd.Parameters.Add("@x", SqlDbType.Int).Direction = ParameterDirection.Output;
cmd.Parameters.Add("@retval", SqlDbType.Int).Direction = ParameterDirection.ReturnValue;

cmd.Execute();
int? x = cmd.Parameters["@x"].Value is DBNull ? null : (int?)cmd.Parameters["@x"].Value;

Тогда x будет содержать null. Чтобы он работал, вам необходимо выполнить следующую процедуру:

using (var rdr = cmd.ExecuteReader()) {
    while (rdr.Read())
        MaybeDoSomething;
}
int? x = cmd.Parameters["@x"].Value is DBNull ? null : (int?)cmd.Parameters["@x"].Value;

В последнем случае x будет содержать 1, как ожидалось.

Question

Вероятно, это простой ответ. У меня есть эта процедура:

CREATE PROCEDURE [dbo].[AccountExists]
    @UserName nvarchar(16)
AS
IF EXISTS (SELECT Id FROM Account WHERE UserName=@UserName)
SELECT 1
ELSE SELECT 0 

Когда у меня есть код ADO.NET, который вызывает эту процедуру, и делает следующее:

return Convert.ToBoolean(sproc.ExecuteScalar());

Возвращается либо true, либо false.

Когда я меняю хранимую процедуру на RETURN 1 или 0 вместо SELECT:

ALTER PROCEDURE [dbo].[AccountExists]
    @UserName nvarchar(16)
AS
IF EXISTS (SELECT Id FROM Account WHERE UserName=@UserName)
RETURN 1
ELSE RETURN 0 

sproc.ExecuteScalar () возвращает значение null. Если я попробую sproc.ExecuteNonQuery (), то возвращается -1.

Как получить результат хранимой процедуры с помощью RETURN в ADO.NET?

Мне нужны AccountExists для RETURN вместо SELECT, поэтому я могу использовать другую хранимую процедуру:

--another procedure to insert or update account

DECLARE @exists bit

EXEC @exists = [dbo].[AccountExists] @UserName 

IF @exists=1
--update account
ELSE
 --insert acocunt



Я пробовал другие решения с моей настройкой, и они не работали, но я использую VB6 & ADO 6.x. Я также хочу отметить, что результат возврата 0 указывает на успешность. Не забывайте, что есть также функции, которые не имеют этого соглашения. Нашел это на MSDN, и это сработало для меня:

Debug.Print "starting at ..." & TimeValue(Now)

Dim cn As New ADODB.Connection
Dim cmd As New ADODB.Command
'These are two possible connection strings. You could also have Integrated Security instead of these for SqS for security
'cn.ConnectionString = "Data Source=[yourserver];User ID=[youruser];Password=[yourpw];Initial Catalog=[yourdb];Provider=SQLNCLI10.1;Application Name=[yourapp]"
cn.ConnectionString = "Data Source=[yours];User ID=[youruser];Password=[yourpassword];Initial Catalog=[Yourdb];Provider=sqloledb;Application Name=[yourapp]"
cn.Open

cmd.ActiveConnection = cn
cmd.CommandText = "AccountExists"
cmd.CommandType = adCmdStoredProc
cmd.Parameters.Append cmd.CreateParameter(, adInteger, adParamReturnValue)
cmd.Parameters.Append cmd.CreateParameter("UserName",adVarChar, adParamInput, 16, UserNameInVB)

cmd.Execute
Debug.Print "Returnval: " & cmd.Parameters(0)
cn.Close

Set cmd = Nothing
Set cn = Nothing

Debug.Print "finished at ..." & TimeValue(Now)

Результаты будут отображаться в непосредственном окне при запуске (Debug.Print)




Если вы планируете использовать его, как в примере ниже, AccountExists может быть лучше как функция.

В противном случае вы все равно сможете получить результат хранимой процедуры, вызвав ее из другой, выполнив выбор в результате.