Làm thế nào để có được kết quả sp_executesql thành một biến?


178

Tôi có một đoạn SQL động tôi cần thực thi, sau đó tôi cần lưu trữ kết quả vào một biến.

Tôi biết tôi có thể sử dụng sp_executesqlnhưng không thể tìm thấy các ví dụ rõ ràng xung quanh về cách thực hiện việc này.

Câu trả lời:


253

Nếu bạn có các tham số OUTPUT, bạn có thể làm

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;

Nhưng nếu bạn không và không thể sửa đổi SP:

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

Không xinh, nhưng hoạt động.


sp của tôi sẽ là sp_executesql @myQuery
JohnIdol

1
@retvalOUT=@retval OUTPUT? Không nên tham số thứ ba của sp_executesqlchỉ là @retval OUTPUT?
Mohammad Deh Afghanistan

2
Chỉ là một câu hỏi tiếp tuyến, còn hơn một OUTPUT thì sao? Truy vấn sẽ như thế nào?
Srivastav

3
@SrivastavReddy Tôi không hiểu làm thế nào câu trả lời này có thể nhận được nhiều sự ủng hộ này. Kiểm tra câu trả lời của Nishanth ..
sotn

2
Tôi nghĩ điều này là chính xác: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

Tôi đã sử dụng phương pháp này trước đây. Nó chỉ có vẻ làm việc trên đầu tiên insert into @tab. Nếu bạn cố gắng insert into @tabvà chạy nhiều execute sp_executesql, với sql khác nhau, select * from @tabchỉ hiển thị kết quả của lần thực hiện đầu tiên
Mike Causer

Rất tiếc, xấu của tôi. Có lỗi trong lựa chọn thứ 2 của tôi, điều đó có nghĩa là nó trả về hàng 0. Phương pháp này hoạt động rất tốt và không yêu cầu bảng tạm thời!
Mike gây ra

Đây là câu trả lời tốt nhất. Mặc dù tôi cần chạy SQL động, điều đó có nghĩa là bạn cần xây dựng SQL động của mình thành một tham số trước tiên, ví dụ: Khai báo @Query nvarchar (255) = N'Select 20 '- sau đó chỉ đơn giản là sl_executeSql chuyển tham số.
Josh Harris

Giải pháp này là giải pháp tốt nhất, tôi đã thử nhiều cách khác và đây là giải pháp DUY NHẤT làm việc cho tôi. Cảm ơn 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
Khai báo biến viOUTPUT và viINT ở đâu?
Jeson Martajaya

1
Cái này làm việc cho tôi Câu trả lời với nhiều phiếu hơn đã không hoạt động
sh_kamalh

5
Tham số @vQuery PHẢI được khai báo là NVARCHAR chứ không phải VARCHAR.
Farzad Karimi


3

Các giá trị trả về thường không được sử dụng để "trả về" kết quả mà trả về thành công (0) hoặc số lỗi (1-65K). Tất cả những điều trên dường như chỉ ra rằng sp_executesql không trả về giá trị, điều này không đúng. sp_executesql sẽ trả về 0 cho thành công và bất kỳ số nào khác cho thất bại.

Ở bên dưới, @i sẽ trả lại 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 sẽ hiển thị Msg 2727, Cấp 11, Trạng thái 1, Dòng 1 Không thể tìm thấy chỉ mục 'NonExistantStaticsName'.


2

KHAI THÁC @ValueTable BẢNG (Giá trị 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

Nếu bạn muốn trả về nhiều hơn 1 giá trị, hãy sử dụng:

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;

các giá trị được trả về nằm trong @ret Index và @retText


1

Đây là thứ bạn có thể thử

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

Điều này đã có từ lâu, vì vậy không chắc chắn liệu điều này có còn cần thiết hay không, nhưng bạn có thể sử dụng biến @@ ROWCOUNT để xem có bao nhiêu hàng bị ảnh hưởng với câu lệnh sql trước đó.

Điều này hữu ích khi ví dụ bạn xây dựng một câu lệnh Cập nhật động và chạy nó với exec. @@ ROWCOUNT sẽ hiển thị số lượng hàng đã được cập nhật.

Đây là định nghĩa


0

Điều này làm việc cho tôi:

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.