web-dev-qa-db-fra.com

Problème de paramètre de sortie SQL Server

J'utilise SQL Server 2008 Enterprise. J'apprends le paramètre OUTPUT de la procédure stockée SQL Server. Par exemple, la procédure stockée sp_add_jobschedule a un paramètre OUTPUT appelé schedule_id.

http://msdn.Microsoft.com/en-us/library/ms366342.aspx

Ma confusion est, semble que le paramètre OUTPUT pourrait être fourni une valeur d'entrée et renvoie également une valeur, semble qu'il a des comportements à la fois INPUT et OUTPUT paramètre? Est-il permis de ne fournir aucune valeur INPUT pour le paramètre OUTPUT (pour lui donner l'apparence d'un comportement de paramètre de sortie pur)?

32
George2

La confusion est justifiée dans une certaine mesure - et d'autres SGBDR, comme Oracle, ont des paramètres de procédure stockée pouvant être de type IN (entrée uniquement), OUT (sortie uniquement) ou INOUT (les deux méthodes - type de paramètre "passe par référence") .

SQL Server est un peu bâclé ici car il attribue le paramètre OUTPUT, mais en réalité, cela signifie INPUT/OUTPUT - cela signifie simplement que le proc stocké a une chance de renvoyer une valeur de son appel dans ce paramètre.

Donc, oui - même s'il s'appelle paramètre OUTPUT, il s'agit en réalité d'un paramètre INPUT/OUTPUT, et ces IN, INOUT, OUT comme dans Oracle n'existent pas dans SQL Server (dans T-SQL).

60
marc_s

Je peux vous donner un court exemple sur la façon de créer une procédure stockée avec un paramètre de sortie.

CREATE PROCEDURE test_proc

@intInput int,
@intOutput int OUTPUT

AS
set @intOutput = @intInput + 1 

go

Et pour appeler cette procédure puis utiliser le paramètre de sortie, procédez comme suit:

declare @intResult int
exec test_proc 3 ,@intResult OUT
select @intResult

Vous voyez que vous devez déclarer la variable de sortie en premier. Et après l'exécution de la procédure stockée, la valeur de sortie sera dans votre variable. Vous pouvez définir n'importe quelle valeur pour votre variable de sortie, mais après l'exécution de la procédure stockée, celle-ci contiendra exactement le retour de la procédure stockée (quelle que soit la valeur de la variable de sortie).

Par exemple:

declare @intResult int
exec test_proc 3 ,@intResult OUT
select @intResult

Il reviendra 4. Et:

declare @intResult int
set @intResult = 8
exec test_proc 3 ,@intResult OUT
select @intResult

Également retourner 4.

19
Sergey Olontsev

Oui, vous pouvez utiliser un paramètre OUTPUT pour transmettre et récupérer des valeurs (bien que je ne puisse pas penser à une bonne raison de le faire pour le moment).

Voici un exemple trivial qui montre ceci:

-- The stored procedure
CREATE PROCEDURE OutParamExample
    @pNum int OUTPUT
AS
BEGIN
    select @pNum
    set @pNum = @pNum + 5
END
GO

-- use a local variable to retrieve your output param value
declare @TheNumber int
set @TheNumber = 10

print @TheNumber
exec OutParamExample @TheNumber OUTPUT
print @TheNumber

Les résultats ressembleront à ceci:

10

-----------
10

(1 row(s) affected)

15

EDIT: OK, je pense avoir manqué un "non" au deuxième paragraphe et je n’ai peut-être pas répondu à la question que vous avez posée. Si vous voulez un paramètre de sortie strict (par exemple, un code de retour, par exemple), vous n'avez certainement pas besoin de fournir value à la variable locale transmise comme paramètre de sortie, mais vous devez quand même déclarer cette variable locale. vous aurez accès à la valeur renvoyée en dehors de la procédure elle-même.

Par exemple:

declare @LocalNumber int
-- I don't have to assign a value to @LocalNumber to pass it as a parameter
exex OutParamExample @LocalNumber OUTPUT  
-- (assume SP has been altered to assign some reasonable value)

-- but I do have to declare it as a local variable so I can get to
-- the return value after the stored procedure has been called
print @LocalNumber
6
Matt

Ajoutant à ce que d’autres ont dit plus haut, les paramètres OUTPUT peuvent agir à la fois comme INPUT et OUTPUT. Mais, cela dépend de la procédure stockée d’utiliser la valeur qui lui est transmise.

Si les procédures stockées ignorent la valeur transmise pour le paramètre OUTPUT (ce qu'il devrait généralement), la valeur INPUT est ignorée de toute façon.

En utilisant le code de Sergey, je peux utiliser la valeur que l'utilisateur a passée pour @intOutput (si besoin est)

create PROCEDURE test_proc

@intInput int,
@intOutput int OUTPUT

AS
set @intOutput = @intOutput + 1 

go

Mais, cela annule la fonction du paramètre OUTPUT.
Pour donner une vue différente, le compilateur c # vous oblige à écraser la valeur du paramètre out par affectation (sans utiliser le paramètre de sortie).

par exemple. Je ne peux pas faire cela en c #. Ici, il agit uniquement comme paramètre out (c’est-à-dire ignorer la valeur que l’utilisateur a transmise à cette fonction)

static void dosomething(out int i)
{
    //i = 0;
    i = i + 1;
}
3
shahkalpesh

La question est - pourquoi voulez-vous refuser d’apporter votre contribution? Cela n'a aucun sens. Considérez cet exemple simple:

CREATE PROCEDURE test (@param AS INT OUTPUT) AS
BEGIN
  SET @param = 100
END
GO

DECLARE @i INT
SET @i = 0

EXECUTE test @i OUTPUT
PRINT @i

DROP PROCEDURE test

Cette imprime

100

Voir - comment êtes-vous censé obtenir une valeur out si vous ne mettez pas une variable in first?

2
Tomalak

Pensez aux paramètres de sortie tels qu'ils sont transmis par référence dans les langages de programmation, c'est la même chose. Le meilleur exemple que je puisse penser maintenant est le renvoi du code d'erreur. Vous voulez insérer ... si vous sélectionnez le code de retour dans SP vous devez le récupérer dans votre code, avec le paramètre OUTPUT que vous n'avez pas, il sera déjà dans votre paramètre (I signifie en utilisant les commandes C #, PHP init met des méthodes proc stockées, ou quelque chose de différent de la construction de chaînes)

2
Svetlozar Angelov

Une note supplémentaire concernant une partie de la question initiale:

"Est-il permis de ne fournir aucune valeur INPUT pour le paramètre OUTPUT (..)?"

Dans SQLServer, il est possible de spécifier une valeur par défaut pour un paramètre OUTPUT (qui, comme d'autres l'ont indiqué, indique INOUT). Prenons l'exemple suivant dans lequel vous pouvez spécifier une valeur explicite ou laisser la fonction générer elle-même un ID. 

CREATE PROCEDURE test (@id uniqueidentifier = NULL OUTPUT) AS
BEGIN
  IF @id IS NULL SET @id = NEWID()
  -- INSERT INTO xyz (...) VALUES (@id, ...)
  PRINT 'Insert with id: ' + CAST (@id as nvarchar(36))
END
GO

DECLARE @insertedId uniqueidentifier
EXECUTE test '00000000-0000-0000-0000-000000000000'
EXECUTE test @insertedId OUTPUT
PRINT @insertedId

DROP PROCEDURE test

Cette imprime

Insert with id: 00000000-0000-0000-0000-000000000000
Insert with id: 67AE3D27-8EAB-4301-B384-30EEA1488440
67AE3D27-8EAB-4301-B384-30EEA1488440
2
blueling

Deux autres choses qui, je pense, méritent d’être signalées:

1) Vous pouvez transmettre plusieurs paramètres sous la forme OUTPUT,

2) Vous n’avez pas à appeler les paramètres avec OUTPUT si vous ne voulez pas les résultats

CREATE PROCEDURE ManyOutputs @a int, @b int output, @c varchar(100) output, @d bit output
AS
BEGIN
    SET @b = @a + 11
    SET @c = 'The Value of A is ' + CAST(@a AS varchar(5)) + ', and the value of B is ' + CAST(@b AS varchar(5))
    IF (@a % 2 = 1)
        SET @d = 1
    ELSE
        SET @d = 0
END
GO

Appelant cette routine:

DECLARE @bVal int
DECLARE @cVal varchar(100)
DECLARE @dVal bit

EXEC ManyOutputs 1, @bVal, @cVal, @dVal
SELECT @bVal AS bVal, @cVal as cVal, @dVal as dVal

Renvoie NULL, NULL, NULL

EXEC ManyOutputs 2, @bVal OUT, @cVal OUT, @dVal OUT
SELECT @bVal AS bVal, @cVal as cVal, @dVal as dVal

Retourne 13, "La valeur de A est 2 et la valeur de B est 13", 0

EXEC ManyOutputs 3, @bVal, @cVal, @dVal
SELECT @bVal AS bVal, @cVal as cVal, @dVal as dVal

Retourne 13, "La valeur de A est 2 et la valeur de B est 13", 0

(identique au dernier appel, car nous n'avons pas obtenu de nouvelles valeurs en utilisant OUTPUT, ainsi les anciennes valeurs ont été conservées.) 

EXEC ManyOutputs 5, @bVal OUT, @cVal OUT, @dVal OUT
SELECT @bVal AS bVal, @cVal as cVal, @dVal as dVal

Retourne 16, "La valeur de A est 5 et la valeur de B est 16", 1

0
Dan