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.


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

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. :-)


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


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

Czym różni się to od powyższej odpowiedzi @ AaronBertrand?
Max Vernon,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.