¿Cómo obtener el resultado sp_executesql en una variable?

178

Tengo una pieza de SQL dinámico que necesito ejecutar, luego necesito almacenar el resultado en una variable.

Sé que puedo usar, sp_executesqlpero no puedo encontrar ejemplos claros sobre cómo hacer esto.

JohnIdol
fuente

Respuestas:

253

Si tiene parámetros de SALIDA puede hacer

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;

Pero si no lo hace, y no puede modificar el SP:

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

No es bonito, pero funciona.

Eduardo Molteni
fuente
mi sp será sp_executesql @myQuery
JohnIdol
1
@retvalOUT=@retval OUTPUT? ¿No debería sp_executesqlser justo el tercer parámetro de la @retval OUTPUT?
Mohammad Dehghan
2
Solo una pregunta tangencial, ¿Qué pasa con más de una SALIDA? ¿Cómo sería la consulta?
Srivastav
3
@SrivastavReddy No entiendo cómo puede esta respuesta obtener tantos votos positivos. Verifique la respuesta de Nishanth ..
sotn
2
Creo que esto es correcto: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
fuente
He usado este método antes. Solo parece funcionar en el primero insert into @tab. Si intenta insert into @tabejecutar múltiples execute sp_executesql, con diferentes sql, select * from @tabsolo muestra los resultados de la primera ejecución
Mike Causer,
Oops, mi mal. Hubo un error en mi segunda selección, lo que significaba que estaba devolviendo cero filas. ¡Este método funciona muy bien y no requiere una tabla temporal!
Mike Causer
Esta es la mejor respuesta. Aunque necesitaba ejecutar SQL dinámico, lo que significa que primero debe construir su SQL dinámico en un parámetro, es decir, Declare @SQL nvarchar (255) = N'Select 20 ', luego simplemente sl_executeSql pasando el parámetro en su lugar.
Josh Harris
Esta solución es la mejor, probé muchas otras y esta es la ÚNICA que funcionó para mí. Gracias 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
fuente
8
¿Dónde está la declaración de las variables viOUTPUT y viINT?
Jeson Martajaya
1
Este me funcionó. La respuesta con más votos no funcionó
sh_kamalh
55
El parámetro @vQuery DEBE declararse como NVARCHAR no como VARCHAR.
Farzad Karimi
3

Declarar @variable int

Exec @variable = nombre_proc

Mark Hedley
fuente
3

Los valores de retorno generalmente no se usan para "devolver" un resultado, sino para devolver el éxito (0) o un número de error (1-65K). Todo lo anterior parece indicar que sp_executesql no devuelve un valor, que no es correcto. sp_executesql devolverá 0 para el éxito y cualquier otro número para el fracaso.

En el siguiente, @i devolverá 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 mostrará este mensaje 2727, nivel 11, estado 1, línea 1 No se puede encontrar el índice 'NonExistantStaticsName'.

PseudoToad
fuente
2

DECLARE @ValueTable TABLE (Valor 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
fuente
2

Si desea devolver más de 1 valor, use esto:

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;

los valores devueltos están en @retIndex y @retText

cihata87
fuente
1

Aquí hay algo que puedes probar

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
fuente
0

Esto fue hace mucho tiempo, por lo que no estoy seguro de si todavía es necesario, pero podría usar la variable @@ ROWCOUNT para ver cuántas filas se vieron afectadas con la instrucción sql anterior.

Esto es útil cuando, por ejemplo, construye una instrucción de actualización dinámica y la ejecuta con exec. @@ ROWCOUNT mostraría cuántas filas se actualizaron.

Aquí está la definición

bazsano1
fuente
0

Esto funcionó para mí:

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
fuente