Могу ли я иметь необязательный выходной параметр в хранимой процедуре?

у меня есть хранимая процедура, которая имеет кучу входных и выходных параметров, потому что она вставляет значения в несколько таблиц. В некоторых случаях сохраненный proc вставляется только в одну таблицу (в зависимости от входных параметров). Вот переделала сценарий, чтобы проиллюстрировать.

Таблицы / Объекты Данные:

человек

Id
Name
Address

имя

Id
FirstName
LastName

адрес

Id
Country
City

Сказать, Что Я имейте хранимую процедуру, которая вставляет человека. Если адрес не существует, я не буду добавлять его в Address таблицы в базе данных.

таким образом, когда я генерирую код для вызова хранимой процедуры, я не хочу добавлять

5 ответов


как входные, так и выходные параметры могут быть присвоены значения по умолчанию. В этом примере:

CREATE PROCEDURE MyTest
  @Data1 int
 ,@Data2 int = 0
 ,@Data3 int = null output

AS

PRINT @Data1
PRINT @Data2
PRINT isnull(@Data3, -1)

SET @Data3 = @Data3 + 1

RETURN 0

первый параметр является обязательным, а второе и третье не обязательно, если не установлен при вызове подпрограммы, им будут присваиваться значения по умолчанию. Попробуйте возиться с ним и следующей процедурой тестового вызова в SSMS, используя разные значения и настройки, чтобы увидеть, как все это работает вместе.

DECLARE @Output int

SET @Output = 3

EXECUTE MyTest
  @Data1 = 1
 ,@Data2 = 2
 ,@Data3 = @Output output

PRINT '---------'
PRINT @Output

выходные параметры и значения по умолчанию не работают хорошо вместе! Это из SQL 10.50.1617 (2008 R2). не обольщайтесь полагать, это волшебно устроена не SET к этому значению от вашего имени (как и мой коллега)!

эта "игрушка" SP допрашивает OUTPUT значение параметра, будь то значение по умолчанию или NULL.

CREATE PROCEDURE [dbo].[omgwtf] (@Qty INT, @QtyRetrieved INT = 0 OUTPUT)
AS
IF @QtyRetrieved = 0
BEGIN
    print 'yay its zero'
END
IF @QtyRetrieved is null
BEGIN
    print 'wtf its NULL'
END
RETURN

если вы отправляете неинициализированное значение (т. е. NULL) для OUTPUT, вы на самом деле got NULL внутри SP, а не 0. Имеет смысл, что-то прошло для этого параметра.

declare @QR int
exec [dbo].[omgwtf] 1, @QR output
print '@QR=' + coalesce(convert(varchar, @QR),'NULL')

вывод:

wtf its NULL
@QR=NULL

если мы добавим явный SET от абонента мы получаем:

declare @QR int
set @QR = 999
exec [dbo].[omgwtf] 1, @QR output
print '@QR=' + coalesce(convert(varchar, @QR),'NULL')

и (неудивительно) выход:

@QR=999

опять же, имеет смысл, параметр передается, и SP не предпринял никаких явных действий для SET значение.

добавить SET на OUTPUT параметр в SP (как вы предполагается сделать), но не устанавливайте ничего от вызывающего абонента:

ALTER PROCEDURE [dbo].[omgwtf] (@Qty INT, @QtyRetrieved INT = 0 OUTPUT)
AS
IF @QtyRetrieved = 0
BEGIN
    print 'yay its zero'
END
IF @QtyRetrieved is null
BEGIN
    print 'wtf its NULL'
END
SET @QtyRetrieved = @Qty
RETURN

теперь при выполнении:

declare @QR int
exec [dbo].[omgwtf] 1234, @QR output
print '@QR=' + coalesce(convert(varchar, @QR),'NULL')

выход:

wtf its NULL
@QR=1234

это "стандартное" поведение для OUTPUT обработка параметров в SPs.

теперь поворот сюжета: единственный способ получить значение по умолчанию для "активировать" - это не пройдет OUTPUT параметр вообще, что ИМХО имеет мало смысла: поскольку он настроен как OUTPUT параметр, что означало бы возврат чего-то" важного", что должно быть собрано.

declare @QR int
exec [dbo].[omgwtf] 1
print '@QR=' + coalesce(convert(varchar, @QR),'NULL')

дает этот выход:

yay its zero
@QR=NULL

но это не удается захватить выход SPs, предположительно, цель этого SP для начала.

ИМХО эта функция сочетанием сомнительный конструкт я бы считал код запах (фух!!)


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

@AddressId int = -1 Output

кажется, что его плохо с точки зрения читаемости, так как AddressId предназначен строго как OUTPUT переменной. Но это работает. Пожалуйста, дайте мне знать, если есть лучшее решение.


добавление к тому, что сказал Филипп:

у меня была хранимая процедура в моей базе данных sql server, которая выглядела следующим образом:

dbo.<storedProcedure>
(@current_user char(8) = NULL,
@current_phase char(3) OUTPUT)

и я вызывал его из своего .net-кода следующим образом:

 DataTable dt = SqlClient.ExecuteDataTable(<connectionString>, <storedProcedure>);

я получал систему.Данные.В sqlclient.SqlException: процедура или функция ожидает параметр '@current_phase', который не был предоставлен.

Я также использую эту функцию где-то еще в моей программе и передаю параметр и обработка выходного. Чтобы мне не пришлось изменять текущий вызов, я просто изменил хранимую процедуру, чтобы сделать выходной параметр также необязательным.

Итак, теперь это выглядит следующим образом:

dbo.<storedProcedure>
(@current_user char(8) = NULL,
@current_phase char(3) = NULL OUTPUT)

поскольку вы выполняете хранимую процедуру, а не инструкцию SQL, вы должны установить тип команды вашей команды SQL в хранимую процедуру:

cmd.CommandType = CommandType.StoredProcedure;

принято от здесь.

кроме того, как только вы удалите эту ошибку, вы можете использовать SQL nvl() функция в вашей процедуре, чтобы указать, что вы хотите отобразить, когда встречается нулевое значение.

извините за неправильное решение вопроса...должно быть, неправильно вас понял. Вот пример nvl, который, я думаю, может решить его немного лучше?

select NVL(supplier_city, 'n/a')
from suppliers;

оператор SQL выше вернет 'n / a', если supplier_city поле содержит значение null. В противном случае он вернет supplier_city значение.