Jaki jest najłatwiejszy sposób utworzenia tabeli tymczasowej w programie SQL Server, która może przechowywać wynik procedury przechowywanej?

50

Wiele razy muszę pisać coś takiego, gdy mam do czynienia z programem SQL Server.

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

insert into #table_name
execute some_stored_procedure;

Ale utworzenie tabeli, która ma dokładną składnię w wyniku procedury składowanej, jest żmudnym zadaniem. Na przykład wynik sp_helppublication ma 48 kolumn! Chcę wiedzieć, czy jest na to łatwy sposób.

Dzięki.

Tylko uczeń
źródło
Jeśli chcesz zdefiniować format wyjściowy (a jeśli jesteś DBA, powinieneś preferować zdefiniowany format!), Rozważ UDF o wartości tabeli. Niestety mają one poważne ograniczenia, więc nie zawsze są opcją.
Jon of All Trades

Odpowiedzi:

36

Jeśli procedura zwraca tylko jeden zestaw wyników, a opcja zapytań rozproszonych ad hoc jest włączona.

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

Lub możesz skonfigurować serwer z pętlą zwrotną i używać go zamiast tego.

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

SELECT *
INTO  #T
FROM OPENQUERY(LOCALSERVER, 
               'SET FMTONLY OFF;
               EXEC sp_who')
Martin Smith
źródło
Nie masz na myśli SET FMT_ONLY ON?
Andreas Ågren,
@Andreas - Nie, ponieważ założyłem, że pomysł polega zarówno na utworzeniu, jak i wypełnieniu tabeli na podstawie danych wyjściowych procedury składowanej.
Martin Smith
18

W SQL Server 2012 i nowszych wersjach można używać sys.dm_exec_describe_first_result_setlokalnie, zakładając, że zestaw wyników, którego szukasz, jest pierwszym wynikiem:

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;

Wynik:

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

Uwaga: istnieje ograniczenie: jeśli procedura składowana tworzy tabele #temp, funkcja metadanych nie działa. Dlatego nie użyłem sp_who2. :-)

Aaron Bertrand
źródło
Czy SELECT @sql += *expression*składnia jest gdzieś udokumentowana? należy ORDER BYwłączyć, aby był stabilny?
Ross Presser
1
@ Ross tak, został wprowadzony w SQL Server 2008 i jest tutaj udokumentowany . ORDER BYwiadomo, że czyni to mniej stabilnym . Jeśli chcesz wyników w przewidywalny aby użyć FOR XML PATHlub, jeżeli na wystarczająco nowej wersji SQL Server STRING_AGG.
Aaron Bertrand
1
Niewielka korekta: połączono z arytmetyką +=... ciąg +=jest tutaj udokumentowany . Ale dziękuję!
Ross Presser
@ Ross tak, przepraszam.
Aaron Bertrand
3

Nie. Wynik procedury przechowywanej może się znacznie różnić: nie jest zaprojektowany tak, aby zawsze zwracał dokładnie jeden zestaw wyników jak SELECT dla jakiegoś obiektu.

Państwo musi wykonać CREATE TABLE

gbn
źródło
1

Napiszę procedurę generowania tabeli dla mnie:

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;

Następnie zadzwoń za pomocą:

EXEC p_create_table_from_procedure 'YOUR_TABLE_NAME_HERE', 'YOUR_PROCEDURE_NAME_HERE'

Uwaga : zastąp „YOUR_PROCEDURE_NAME_HERE” nazwą własnej procedury składowanej.

Uwaga : zastąp YOUR_TABLE_NAME_HERE wybraną nazwą tabeli.

Powyższe wygeneruje coś takiego:

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
źródło
Czym różni się to od powyższej odpowiedzi @ AaronBertrand?
Max Vernon,