Qual è il modo più semplice per creare una tabella temporanea in SQL Server in grado di contenere il risultato di una procedura memorizzata?


50

Molte volte ho bisogno di scrivere qualcosa di simile al seguente quando ho a che fare con SQL Server.

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

insert into #table_name
execute some_stored_procedure;

Ma creare una tabella che abbia la sintassi esatta come risultato di una procedura memorizzata è un compito noioso. Ad esempio, il risultato di sp_helppublication ha 48 colonne! Voglio sapere se esiste un modo semplice per farlo.

Grazie.


Se desideri un formato di output definito (e se sei un DBA, dovresti preferire un formato definito!), Considera un UDF a valore di tabella. Sfortunatamente hanno alcune serie limitazioni, quindi non sono sempre un'opzione.
Jon of All Trades,

Risposte:


36

Se la procedura restituisce solo un set di risultati e l' opzione query ad hoc distribuite è abilitata.

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

Oppure puoi configurare un server collegato in loopback e usarlo invece.

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

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

Non intendi SET FMT_ONLY ON?
Andreas Ågren,

@Andreas - No perché ho pensato che l'idea fosse quella di creare e popolare la tabella dall'output della procedura memorizzata.
Martin Smith,

18

In SQL Server 2012 e versioni successive, è possibile utilizzare sys.dm_exec_describe_first_result_setlocalmente, supponendo che il set di risultati desiderato sia il primo risultato:

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;

Risultato:

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

Si noti che esiste una limitazione: se la procedura memorizzata crea tabelle #temp, la funzionalità dei metadati non funziona. Questo è il motivo per cui non ho usato sp_who2. :-)


La SELECT @sql += *expression*sintassi è documentata da qualche parte? dovrebbe ORDER BYessere incluso per renderlo stabile?
Ross Presser,

1
@Ross sì, è stato introdotto in SQL Server 2008 ed è documentato qui . ORDER BYè noto per renderlo meno stabile . Se si desidera che i risultati in un ordine prevedibile, utilizzare FOR XML PATHo, se su una nuova versione di SQL Server sufficiente, STRING_AGG.
Aaron Bertrand

1
Leggera correzione: hai collegato all'aritmetica +=... la stringa +=è documentata qui . Ma grazie!
Ross Presser,

@Ross yup, sorry.
Aaron Bertrand

3

No. Il risultato di una procedura memorizzata può variare notevolmente: non è progettato per restituire sempre esattamente un set di risultati come un SELECT su un oggetto.

È necessario eseguire CREATE TABLE


1

Scriverei una procedura per generare la tabella per me:

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;

Quindi chiamalo con:

EXEC p_create_table_from_procedure 'YOUR_TABLE_NAME_HERE', 'YOUR_PROCEDURE_NAME_HERE'

Nota : sostituire "YOUR_PROCEDURE_NAME_HERE" con il nome della propria procedura memorizzata.

Nota : sostituisci YOUR_TABLE_NAME_HERE con il nome della tabella che preferisci.

Quanto sopra genererà qualcosa del genere:

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

In che cosa differisce dalla risposta di @ AaronBertrand sopra?
Max Vernon,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.