Wie bekomme ich das sp_executesql-Ergebnis in eine Variable?

178

Ich habe ein Stück dynamisches SQL, das ich ausführen muss, und muss dann das Ergebnis in einer Variablen speichern.

Ich weiß, dass ich verwenden kann sp_executesql, kann aber keine klaren Beispiele dafür finden.

JohnIdol
quelle

Antworten:

253

Wenn Sie OUTPUT-Parameter haben, können Sie dies tun

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;

Aber wenn Sie dies nicht tun und den SP nicht ändern können:

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

Nicht schön, funktioniert aber.

Eduardo Molteni
quelle
Mein SP wird sp_executesql @myQuery
JohnIdol
1
@retvalOUT=@retval OUTPUT? Sollte der dritte Parameter sp_executesqlnicht gerecht sein @retval OUTPUT?
Mohammad Dehghan
2
Nur eine tangentiale Frage: Was ist mit mehr als einem AUSGANG? Wie würde die Abfrage aussehen?
Srivastav
3
@SrivastavReddy Ich verstehe nicht, wie diese Antwort so viele positive Stimmen bekommen kann. Überprüfen Sie Nishanths Antwort ..
sotn
2
Ich denke, das ist richtig: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
Nishanth
quelle
Ich habe diese Methode schon einmal verwendet. Es scheint nur beim ersten zu funktionieren insert into @tab. Wenn Sie versuchen, insert into @tabmehrere execute sp_executesqlmit unterschiedlichen SQL auszuführen, werden select * from @tabnur die Ergebnisse der ersten Ausführung angezeigt
Mike Causer
Ups, mein schlechtes. Bei meiner zweiten Auswahl ist ein Fehler aufgetreten, der bedeutet, dass keine Zeilen zurückgegeben wurden. Diese Methode funktioniert hervorragend und erfordert keine temporäre Tabelle!
Mike Causer
Dies ist die beste Antwort. Obwohl ich dynamisches SQL ausführen musste, bedeutet dies, dass Sie Ihr dynamisches SQL zuerst in einen Parameter einbauen müssen, dh @SQL nvarchar (255) = N'Select 20 'deklarieren - und dann einfach sl_executeSql den Parameter übergeben.
Josh Harris
Diese Lösung ist die beste, ich habe viele, viele andere ausprobiert und dies ist die EINZIGE, die für mich funktioniert hat. Vielen Dank, dass Sie 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
Buchaiah
quelle
8
Wo ist die Deklaration der Variablen viOUTPUT und viINT?
Jeson Martajaya
1
Dieser hat für mich gearbeitet. Die Antwort mit mehr Stimmen hat nicht funktioniert
sh_kamalh
5
Der Parameter @vQuery MUSS als NVARCHAR und nicht als VARCHAR deklariert werden.
Farzad Karimi
3

Deklarieren Sie @variable int

Exec @variable = proc_name

Mark Hedley
quelle
3

Rückgabewerte werden im Allgemeinen nicht verwendet, um ein Ergebnis "zurückzugeben", sondern um Erfolg (0) oder eine Fehlernummer (1-65 KB) zurückzugeben. Dies scheint vor allem darauf hinzudeuten, dass sp_executesql keinen Wert zurückgibt, der nicht korrekt ist. sp_executesql gibt 0 für den Erfolg und eine andere Zahl für den Fehler zurück.

Im Folgenden gibt @i 2727 zurück

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 zeigt diese Meldung 2727, Ebene 11, Status 1, Zeile 1 an. Der Index 'NonExistantStaticsName' kann nicht gefunden werden.

PseudoToad
quelle
2

DECLARE @ValueTable TABLE (Wert 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
Abhishek Dheeman
quelle
2

Wenn Sie mehr als einen Wert zurückgeben möchten, verwenden Sie Folgendes:

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;

Die zurückgegebenen Werte befinden sich in @retIndex und @retText

cihata87
quelle
1

Hier ist etwas, das Sie ausprobieren können

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
RecursiveCTE
quelle
0

Dies ist lange her, daher nicht sicher, ob dies noch benötigt wird, aber Sie können die Variable @@ ROWCOUNT verwenden, um zu sehen, wie viele Zeilen von der vorherigen SQL-Anweisung betroffen waren.

Dies ist hilfreich, wenn Sie beispielsweise eine dynamische Update-Anweisung erstellen und mit exec ausführen. @@ ROWCOUNT würde anzeigen, wie viele Zeilen aktualisiert wurden.

Hier ist die Definition

bazsano1
quelle
0

Das hat bei mir funktioniert:

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
Dylan Hayes
quelle