Was ist der einfachste Weg, um eine temporäre Tabelle in SQL Server zu erstellen, die das Ergebnis einer gespeicherten Prozedur enthalten kann?

50

Oft muss ich etwas wie das Folgende schreiben, wenn ich mich mit SQL Server beschäftige.

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

insert into #table_name
execute some_stored_procedure;

Das Erstellen einer Tabelle mit der genauen Syntax als Ergebnis einer gespeicherten Prozedur ist jedoch eine mühsame Aufgabe. Zum Beispiel hat das Ergebnis von sp_helppublication 48 Spalten! Ich möchte wissen, ob es einen einfachen Weg gibt, dies zu tun.

Vielen Dank.

Nur ein Anfänger
quelle
Wenn Sie ein definiertes Ausgabeformat möchten (und wenn Sie ein DBA sind, sollten Sie ein definiertes Format bevorzugen!), Ziehen Sie eine Tabellenwert-UDF in Betracht. Leider haben sie einige schwerwiegende Einschränkungen, so dass sie nicht immer eine Option sind.
Jon of All Trades

Antworten:

36

Wenn die Prozedur nur eine Ergebnismenge zurückgibt und die Option für verteilte Ad-hoc-Abfragen aktiviert ist.

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

Oder Sie können einen Loopback-Verbindungsserver einrichten und diesen stattdessen verwenden.

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

SELECT *
INTO  #T
FROM OPENQUERY(LOCALSERVER, 
               'SET FMTONLY OFF;
               EXEC sp_who')
Martin Smith
quelle
Meinst du nicht SET FMT_ONLY ON?
Andreas Ågren
@Andreas - Nein, da ich davon ausgegangen bin, dass die Tabelle aus der Ausgabe der gespeicherten Prozedur erstellt und aufgefüllt werden soll.
Martin Smith
18

In SQL Server 2012 und höher können Sie sys.dm_exec_describe_first_result_setlokal verwenden, vorausgesetzt, die gewünschte Ergebnismenge ist das erste Ergebnis:

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;

Ergebnis:

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

Beachten Sie, dass es eine Einschränkung gibt: Wenn Ihre gespeicherte Prozedur # temporäre Tabellen erstellt, funktioniert die Metadatenfunktionalität nicht. Aus diesem Grund habe ich sp_who2 nicht verwendet. :-)

Aaron Bertrand
quelle
Ist die SELECT @sql += *expression*Syntax irgendwo dokumentiert? sollte ein ORDER BYenthalten sein, um es stabil zu machen?
Ross Presser
1
@ Ross ja, es wurde in SQL Server 2008 eingeführt und ist hier dokumentiert . ORDER BYEs ist bekannt , dass dies weniger stabil ist . Wenn Sie möchten, dass die Ergebnisse in einer vorhersehbaren Reihenfolge angezeigt werden, verwenden Sie FOR XML PATHoder, wenn die Version von SQL Server neu genug ist STRING_AGG.
Aaron Bertrand
1
Leichte Korrektur: Sie haben mit der arithmetischen +=Zeichenfolge verknüpft . Hier+= wird dokumentiert . Aber danke!
Ross Presser
@ Ross yup, sorry.
Aaron Bertrand
3

Nein. Das Ergebnis einer gespeicherten Prozedur kann sehr unterschiedlich sein: Es ist nicht so konzipiert, dass immer genau eine Ergebnismenge wie ein SELECT für ein Objekt zurückgegeben wird.

Sie müssen CREATE TABLE ausführen

gbn
quelle
1

Ich würde eine Prozedur schreiben, um die Tabelle für mich zu generieren:

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;

Dann nenne es mit:

EXEC p_create_table_from_procedure 'YOUR_TABLE_NAME_HERE', 'YOUR_PROCEDURE_NAME_HERE'

Hinweis : Ersetzen Sie "YOUR_PROCEDURE_NAME_HERE" durch den Namen Ihrer eigenen gespeicherten Prozedur.

Hinweis : Ersetzen Sie YOUR_TABLE_NAME_HERE durch den Tabellennamen Ihrer Wahl.

Das oben Genannte wird ungefähr so ​​aussehen:

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
quelle
Wie unterscheidet sich das von der obigen Antwort von @ AaronBertrand?
Max Vernon