Cách dễ nhất để tạo bảng tạm thời trong SQL Server có thể giữ kết quả của một thủ tục được lưu trữ là gì?


50

Nhiều lần tôi cần phải viết một cái gì đó như sau khi làm việc với SQL Server.

create table #table_name
(
    column1 int,
    column2 varchar(200)
    ...
)

insert into #table_name
execute some_stored_procedure;

Nhưng tạo một bảng có cú pháp chính xác là kết quả của một thủ tục được lưu trữ là một nhiệm vụ tẻ nhạt. Ví dụ: kết quả của sp_helppublication có 48 cột! Tôi muốn biết liệu có cách nào dễ dàng để làm điều này.

Cảm ơn.


Nếu bạn muốn một định dạng đầu ra được xác định (và nếu bạn là một DBA, bạn nên thích một định dạng xác định!), Hãy xem xét một UDF giá trị bảng. Thật không may, chúng có một số hạn chế nghiêm trọng, vì vậy chúng không phải lúc nào cũng là một lựa chọn.
Jon của tất cả các giao dịch

Câu trả lời:


36

Nếu thủ tục chỉ trả về một tập kết quả và tùy chọn truy vấn phân tán ad hoc được bật.

SELECT * 
INTO #T 
FROM OPENROWSET('SQLNCLI', 
                'Server=(local)\MSSQL2008;Trusted_Connection=yes;',
                 'SET FMTONLY OFF;EXEC sp_who')

Hoặc bạn có thể thiết lập một máy chủ được liên kết loopback và sử dụng nó thay thế.

EXEC sp_addlinkedserver @server = 'LOCALSERVER',  @srvproduct = '',
                        @provider = 'SQLNCLI', @datasrc = @@servername

SELECT *
INTO  #T
FROM OPENQUERY(LOCALSERVER, 
               'SET FMTONLY OFF;
               EXEC sp_who')

Ý bạn là SET FMT_ONLY ONsao?
Andreas gren

@Andreas - Không bởi vì tôi cho rằng ý tưởng là vừa tạo và điền vào bảng từ đầu ra thủ tục được lưu trữ.
Martin Smith

18

Trong SQL Server 2012 trở lên, bạn có thể sử dụng sys.dm_exec_describe_first_result_setcục bộ, giả sử tập kết quả bạn theo sau là kết quả đầu tiên :

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += ',' + CHAR(13) + CHAR(10) + CHAR(9)
    + name + ' ' + system_type_name
    FROM sys.dm_exec_describe_first_result_set('sp_who', NULL, 1);

SELECT @sql = N'CREATE TABLE #f
(' + STUFF(@sql, 1, 1, N'') + '
);';

PRINT @sql;

Kết quả:

CREATE TABLE #f
(
    spid smallint,
    ecid smallint,
    status nchar(30),
    loginame nvarchar(128),
    hostname nchar(128),
    blk char(5),
    dbname nvarchar(128),
    cmd nchar(16),
    request_id int
);

Lưu ý có một hạn chế: nếu quy trình được lưu trữ của bạn tạo các bảng #temp, chức năng siêu dữ liệu không hoạt động. Đây là lý do tại sao tôi không sử dụng sp_who2. :-)


SELECT @sql += *expression*cú pháp tài liệu ở đâu đó? nên ORDER BYđược bao gồm để làm cho nó ổn định?
Ross Presser

1
@Ross có, nó đã được giới thiệu trong SQL Server 2008 và được ghi lại ở đây . ORDER BYthực sự được biết là làm cho điều này kém ổn định . Nếu bạn muốn kết quả theo thứ tự dự đoán, hãy sử dụng FOR XML PATHhoặc, nếu trên phiên bản SQL Server đủ mới , STRING_AGG.
Aaron Bertrand

1
Hiệu chỉnh nhẹ: bạn đã liên kết với số học +=... chuỗi +=được ghi lại ở đây . Nhưng cảm ơn bạn!
Ross Presser

@Ross yup, xin lỗi.
Aaron Bertrand

3

Không. Kết quả của một thủ tục được lưu trữ có thể thay đổi một cách dữ dội: nó không được thiết kế để luôn trả về chính xác một tập kết quả như CHỌN trên một số đối tượng.

Bạn phải thực hiện TẠO BẢNG


1

Tôi sẽ viết một thủ tục để tạo bảng cho tôi:

CREATE PROCEDURE [dbo].[p_create_table_from_procedure]
    @TABLE_NAME AS NVARCHAR(MAX),
    @PROCEDURE_NAME AS NVARCHAR(MAX)

As
    DECLARE @CREATE_TABLE_QUERY NVARCHAR(MAX) = N'';


    SELECT 
        @CREATE_TABLE_QUERY += ', ' + name + ' ' + UPPER(system_type_name) + CHAR(13) + CHAR(10) + CHAR(9)

    FROM 
        sys.dm_exec_describe_first_result_set(@procedure_name, NULL, 1);


    SELECT 
        @CREATE_TABLE_QUERY = N'CREATE TABLE ' + @table_name + '(' + CHAR(13) + CHAR(10) + CHAR(9) + STUFF(@CREATE_TABLE_QUERY, 1, 1, N'') + ');';

    PRINT @CREATE_TABLE_QUERY;

Sau đó gọi nó bằng:

EXEC p_create_table_from_procedure 'YOUR_TABLE_NAME_HERE', 'YOUR_PROCEDURE_NAME_HERE'

Lưu ý : Thay thế 'Your_PROCEDURE_NAME_HERE' bằng tên của thủ tục được lưu trữ của riêng bạn.

Lưu ý : Thay thế YOU_TABLE_NAME_HERE bằng tên bảng bạn chọn.

Ở trên sẽ tạo ra một cái gì đó như thế này:

CREATE TABLE YOUR_TABLE_NAME_HERE(
     WeekName VARCHAR(40)
    , Line Name VARCHAR(50)
    , TheDate DATETIME
    , ReceivedAll INT
    , Answered INT
    , Abandoned INT
    , Call Length INT
    , WaitTimeAnswer INT
    , WaitTimeAbandon INT
    , PeriodName VARCHAR(10)
    , Week SMALLINT
    , Period SMALLINT
    , Year SMALLINT
    , WeekInPeriod SMALLINT
    , NumWeeksInPeriod SMALLINT
    , WeekendDate DATETIME
    , CRCOperative VARCHAR(100)
    , CallType VARCHAR(20)
    , Charge Time INT
    , SourceNumber VARCHAR(80)
    , DestinationNumber VARCHAR(80)
    , CallStart DATETIME
    , Out of Hours VARCHAR(12)
    , IsWorkingDay BIT
    );

Điều này khác với câu trả lời của @ AaronBertrand ở trên như thế nào?
Max Vernon
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.