Как получить возвращаемое значение хранимой процедуры - PullRequest
33 голосов
/ 15 апреля 2009

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

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 () возвращает ноль. Если я вместо этого попробую sproc.ExecuteNonQuery (), возвращается -1.

Как получить результат хранимой процедуры с ВОЗВРАТОМ в ADO.NET?

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

--another procedure to insert or update account

DECLARE @exists bit

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

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

Ответы [ 7 ]

42 голосов
/ 15 апреля 2009

Добавьте параметр, используя ParameterDirection.ReturnValue. Возвращаемое значение будет присутствовать в параметре после выполнения.

10 голосов
/ 25 апреля 2009

Кроме того, чтобы получить результат (или любой другой выходной параметр по этому вопросу) из 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 будет содержать ноль. Чтобы это сработало, вы должны выполнить следующую процедуру:

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, как и ожидалось.

3 голосов
/ 15 апреля 2009

ExecuteScalar возвращает первый столбец первой строки. Поскольку вы больше не выбираете и не создаете набор результатов, поэтому он возвращал значение null Так же, как к вашему сведению. Джон Сондерс имеет правильный ответ.

2 голосов
/ 21 сентября 2012

Я попробовал другие решения с моей настройкой, и они не работали, но я использую VB6 и ADO 6.x. Я также хочу отметить, что возвращение proc 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)

1 голос
/ 31 июля 2015

Существует несколько способов получения значений с помощью VBA:

  1. Recordset
  2. Количество затронутых записей (только для вставки / обновления / удаления -1)
  3. Выходной параметр
  4. Возвращаемое значение

Мой код демонстрирует все четыре. Вот хранимая процедура, которая возвращает значение:

Create PROCEDURE CheckExpedite
    @InputX  varchar(10),
    @InputY int,
    @HasExpedite int out
AS
BEGIN
    Select @HasExpedite = 9 from <Table>
    where Column2 = @InputX and Column3 = @InputY

    If @HasExpedite = 9
        Return 2
    Else
        Return 3
End

Вот подпункт, который я использую в Excel VBA. Вам понадобится ссылка на библиотеку Microsoft ActiveX Data Objects 2.8.

Sub CheckValue()

    Dim InputX As String: InputX = "6000"
    Dim InputY As Integer: InputY = 2014

    'open connnection
    Dim ACon As New Connection
    ACon.Open ("Provider=SQLOLEDB;Data Source=<SqlServer>;" & _
        "Initial Catalog=<Table>;Integrated Security=SSPI")

    'set command
    Dim ACmd As New Command
    Set ACmd.ActiveConnection = ACon
    ACmd.CommandText = "CheckExpedite"
    ACmd.CommandType = adCmdStoredProc

    'Return value must be first parameter else you'll get error from too many parameters
    'Procedure or function "Name" has too many arguments specified.
    ACmd.Parameters.Append ACmd.CreateParameter("ReturnValue", adInteger, adParamReturnValue)
    ACmd.Parameters.Append ACmd.CreateParameter("InputX", adVarChar, adParamInput, 10, InputX)
    ACmd.Parameters.Append ACmd.CreateParameter("InputY", adInteger, adParamInput, 6, InputY)
    ACmd.Parameters.Append ACmd.CreateParameter("HasExpedite", adInteger, adParamOutput)

    Dim RS As Recordset
    Dim RecordsAffected As Long

    'execute query that returns value
    Call ACmd.Execute(RecordsAffected:=RecordsAffected, Options:=adExecuteNoRecords)

    'execute query that returns recordset
    'Set RS = ACmd.Execute(RecordsAffected:=RecordsAffected)

    'get records affected, return value and output parameter
    Debug.Print "Records affected: " & RecordsAffected
    Debug.Print "Return value: " & ACmd.Parameters("ReturnValue")
    Debug.Print "Output param: " & ACmd.Parameters("HasExpedite")

    'use record set here
    '...

    'close
    If Not RS Is Nothing Then RS.Close
    ACon.Close

End Sub
1 голос
/ 15 апреля 2009

Просто несколько советов, но по умолчанию хранимая процедура возвращает 0, если не указано иное. По этой причине 0 часто используется для обозначения успеха, а ненулевые значения используются для указания условий возврата. Я бы пошел с предложением Джона , или использовал бы output parameter

0 голосов
/ 15 апреля 2009

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

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

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