Apa cara termudah untuk membuat tabel temporer di SQL Server yang dapat menampung hasil dari prosedur yang tersimpan?

50

Banyak kali saya perlu menulis sesuatu seperti berikut ketika berhadapan dengan SQL Server.

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

insert into #table_name
execute some_stored_procedure;

Tetapi membuat tabel yang memiliki sintaks yang tepat karena hasil dari prosedur tersimpan adalah tugas yang membosankan. Sebagai contoh, hasil sp_helppublication memiliki 48 kolom! Saya ingin tahu apakah ada cara mudah untuk melakukan ini.

Terima kasih.

Hanya seorang pembelajar
sumber
Jika Anda ingin format output yang ditentukan (dan jika Anda seorang DBA, Anda harus memilih format yang ditentukan!), Pertimbangkan UDF nilai-tabel. Sayangnya mereka memiliki beberapa batasan serius, jadi mereka tidak selalu menjadi pilihan.
Jon dari Semua Perdagangan

Jawaban:

36

Jika prosedur hanya mengembalikan satu set hasil dan opsi permintaan yang didistribusikan ad hoc diaktifkan.

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

Atau Anda dapat mengatur server yang ditautkan loopback dan menggunakannya.

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

SELECT *
INTO  #T
FROM OPENQUERY(LOCALSERVER, 
               'SET FMTONLY OFF;
               EXEC sp_who')
Martin Smith
sumber
Bukankah maksud Anda SET FMT_ONLY ON?
Andreas Ågren
@ Andreas - Tidak karena saya berasumsi idenya adalah untuk membuat dan mengisi tabel dari output prosedur tersimpan.
Martin Smith
18

Di SQL Server 2012 dan di atas, Anda dapat menggunakan sys.dm_exec_describe_first_result_setsecara lokal, dengan asumsi hasil yang Anda cari adalah hasil pertama :

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;

Hasil:

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
);

Perhatikan ada batasan: jika prosedur tersimpan Anda membuat tabel #temp, fungsi metadata tidak berfungsi. Inilah sebabnya saya tidak menggunakan sp_who2. :-)

Aaron Bertrand
sumber
Apakah SELECT @sql += *expression*sintaksinya didokumentasikan di suatu tempat? haruskah ORDER BYdimasukkan untuk membuatnya stabil?
Ross Presser
1
@Ross ya, diperkenalkan di SQL Server 2008, dan didokumentasikan di sini . ORDER BYsebenarnya diketahui membuat ini kurang stabil . Jika Anda menginginkan hasil dalam urutan yang dapat diprediksi, gunakan FOR XML PATHatau, jika pada versi SQL Server yang cukup baru STRING_AGG,.
Aaron Bertrand
1
Koreksi sedikit: Anda ditautkan ke +=string ... string +=didokumentasikan di sini . Tapi terima kasih!
Ross Presser
@Ross ya, maaf.
Aaron Bertrand
3

Tidak. Hasil dari prosedur yang disimpan dapat sangat bervariasi: itu tidak dirancang untuk selalu mengembalikan tepat satu hasil yang ditetapkan seperti SELECT pada beberapa objek.

Anda harus menjalankan CREATE TABLE

gbn
sumber
1

Saya akan menulis prosedur untuk menghasilkan tabel untuk saya:

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;

Kemudian sebut dengan:

EXEC p_create_table_from_procedure 'YOUR_TABLE_NAME_HERE', 'YOUR_PROCEDURE_NAME_HERE'

Catatan : Ganti 'YOUR_PROCEDURE_NAME_HERE' dengan nama prosedur tersimpan Anda sendiri.

Catatan : Ganti YOUR_TABLE_NAME_HERE dengan nama tabel pilihan Anda.

Di atas akan menghasilkan sesuatu seperti ini:

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
    );
Knickerless-Noggins
sumber
Bagaimana ini berbeda dari jawaban @ AaronBertrand di atas?
Max Vernon