Comment obtenir le résultat de sp_executesql dans une variable?


178

J'ai un morceau de SQL dynamique que je dois exécuter, je dois ensuite stocker le résultat dans une variable.

Je sais que je peux utiliser, sp_executesqlmais je ne peux pas trouver d'exemples clairs sur la façon de procéder.

Réponses:


253

Si vous avez des paramètres OUTPUT, vous pouvez faire

DECLARE @retval int   
DECLARE @sSQL nvarchar(500);
DECLARE @ParmDefinition nvarchar(500);

DECLARE @tablename nvarchar(50)  
SELECT @tablename = N'products'  

SELECT @sSQL = N'SELECT @retvalOUT = MAX(ID) FROM ' + @tablename;  
SET @ParmDefinition = N'@retvalOUT int OUTPUT';

EXEC sp_executesql @sSQL, @ParmDefinition, @retvalOUT=@retval OUTPUT;

SELECT @retval;

Mais si vous ne le faites pas et ne pouvez pas modifier le SP:

-- Assuming that your SP return 1 value
create table #temptable (ID int null)
insert into #temptable exec mysp 'Value1', 'Value2'
select * from #temptable

Pas joli, mais ça marche.


mon sp sera sp_executesql @myQuery
JohnIdol

1
@retvalOUT=@retval OUTPUT? Le troisième paramètre ne devrait-il pas sp_executesqlêtre juste @retval OUTPUT?
Mohammad Dehghan

2
Juste une question tangentielle, qu'en est-il de plus d'une sortie? à quoi ressemblerait la requête?
Srivastav

3
@SrivastavReddy Je ne comprends pas comment cette réponse peut obtenir autant de votes positifs. Vérifiez la réponse de Nishanth ..
sotn

2
Je pense que c'est correct:EXEC sp_executesql @sSQL, @ParmDefinition, @retval OUTPUT;
Ian

50
DECLARE @tab AS TABLE (col1 VARCHAR(10), col2 varchar(10)) 
INSERT into @tab EXECUTE  sp_executesql N'
SELECT 1 AS col1, 2 AS col2
UNION ALL
SELECT 1 AS col1, 2 AS col2
UNION ALL
SELECT 1 AS col1, 2 AS col2'

SELECT * FROM @tab

J'ai déjà utilisé cette méthode. Cela ne semble fonctionner que sur le premier insert into @tab. Si vous essayez insert into @tabet exécutez plusieurs execute sp_executesql, avec un sql différent, select * from @tabaffiche uniquement les résultats de la première exécution
Mike Causer

Oups, mon mal. Il y avait une erreur dans ma deuxième sélection, ce qui signifiait qu'il ne renvoyait aucune ligne. Cette méthode fonctionne très bien et ne nécessite pas de table temporaire!
Mike Causer

C'est la meilleure réponse. Bien que j'avais besoin d'exécuter du SQL dynamique, ce qui signifie que vous devez d'abord créer votre SQL dynamique dans un paramètre, c'est-à-dire Declare @SQL nvarchar (255) = N'Select 20 '- puis simplement sl_executeSql en passant le paramètre à la place.
Josh Harris

Cette solution est la meilleure, j'en ai essayé beaucoup d'autres et c'est la SEULE qui a fonctionné pour moi. Merci Nishanth
MMEL

40
DECLARE @vi INT
DECLARE @vQuery NVARCHAR(1000)

SET @vQuery = N'SELECT @vi= COUNT(*) FROM <TableName>'

EXEC SP_EXECUTESQL 
        @Query  = @vQuery
      , @Params = N'@vi INT OUTPUT'
      , @vi = @vi OUTPUT

SELECT @vi

8
Où est la déclaration des variables viOUTPUT et viINT?
Jeson Martajaya

1
Celui-ci a fonctionné pour moi. La réponse avec plus de votes n'a pas fonctionné
sh_kamalh

5
Le paramètre @vQuery DOIT être déclaré comme NVARCHAR et non VARCHAR.
Farzad Karimi


3

Les valeurs de retour ne sont généralement pas utilisées pour "renvoyer" un résultat mais pour renvoyer un succès (0) ou un numéro d'erreur (1-65K). Tout cela semble indiquer que sp_executesql ne renvoie pas de valeur, ce qui n'est pas correct. sp_executesql renverra 0 en cas de succès et tout autre nombre en cas d'échec.

Dans ce qui suit, @i renverra 2727

DECLARE @s NVARCHAR(500)
DECLARE @i INT;
SET @s = 'USE [Blah]; UPDATE STATISTICS [dbo].[TableName] [NonExistantStatisticsName];';
EXEC @i = sys.sp_executesql @s
SELECT @i AS 'Blah'

SSMS affichera ce Msg 2727, niveau 11, état 1, ligne 1 Impossible de trouver l'index «NonExistantStaticsName».


2

DECLARE @ValueTable TABLE (Valeur VARCHAR (100))

                    SELECT @sql = N'SELECT SRS_SizeSetDetails.'+@COLUMN_NAME+' FROM SRS_SizeSetDetails WHERE FSizeID = '''+@FSizeID+''' AND SRS_SizeSetID = '''+@SRS_SizeSetID+'''';

                    INSERT INTO @ValueTable
                    EXEC sp_executesql @sql;

                    SET @Value='';

                    SET @Value = (SELECT TOP 1  Value FROM @ValueTable)

                    DELETE FROM @ValueTable

2

Si vous souhaitez renvoyer plus d'une valeur, utilisez ceci:

DECLARE @sqlstatement2      NVARCHAR(MAX);
DECLARE @retText            NVARCHAR(MAX);  
DECLARE @ParmDefinition     NVARCHAR(MAX);
DECLARE @retIndex           INT = 0;

SELECT @sqlstatement = 'SELECT @retIndexOUT=column1 @retTextOUT=column2 FROM XXX WHERE bla bla';

SET @ParmDefinition = N'@retIndexOUT INT OUTPUT, @retTextOUT NVARCHAR(MAX) OUTPUT';

exec sp_executesql @sqlstatement, @ParmDefinition, @retIndexOUT=@retIndex OUTPUT, @retTextOUT=@retText OUTPUT;

les valeurs renvoyées sont dans @retIndex et @retText


1

Voici quelque chose que vous pouvez essayer

DECLARE  @SqlStatement  NVARCHAR(MAX) = ''
       ,@result     XML
       ,@DatabaseName  VARCHAR(100)
       ,@SchemaName    VARCHAR(10)
       ,@ObjectName    VARCHAR(200);

SELECT   @DatabaseName = 'some database'
       ,@SchemaName   = 'some schema'
       ,@ObjectName   = 'some object (Table/View)'

SET @SqlStatement = '
                    SELECT @result = CONVERT(XML,
                                            STUFF( ( SELECT *
                                                     FROM 
                                                       (
                                                          SELECT TOP(100) 
                                                          * 
                                                          FROM ' + QUOTENAME(@DatabaseName) +'.'+ QUOTENAME(@SchemaName) +'.' + QUOTENAME(@ObjectName) + '
                                                       ) AS A1 
                                                    FOR XML PATH(''row''), ELEMENTS, ROOT(''recordset'')
                                                 ), 1, 0, '''')
                                       )
                ';

EXEC sp_executesql @SqlStatement,N'@result XML OUTPUT', @result = @result OUTPUT;

SELECT DISTINCT
    QUOTENAME(r.value('fn:local-name(.)', 'VARCHAR(200)')) AS ColumnName
FROM @result.nodes('//recordset/*/*') AS records(r)
ORDER BY ColumnName

0

C'était il y a longtemps, donc je ne sais pas si cela est toujours nécessaire, mais vous pouvez utiliser la variable @@ ROWCOUNT pour voir combien de lignes ont été affectées par l'instruction sql précédente.

Cela est utile lorsque, par exemple, vous créez une instruction Update dynamique et que vous l'exécutez avec exec. @@ ROWCOUNT afficherait le nombre de lignes mises à jour.

Voici la définition


0

Cela a fonctionné pour moi:

DECLARE @SQL NVARCHAR(4000)

DECLARE @tbl Table (
    Id int,
    Account varchar(50),
    Amount int
) 

-- Lots of code to Create my dynamic sql statement

insert into @tbl EXEC sp_executesql @SQL

select * from @tbl
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.