Inserisci i risultati di una procedura memorizzata in una tabella temporanea


1579

Come faccio a SELECT * INTO [temp table] FROM [stored procedure] ? Non FROM [Table]e senza definizione [temp table]?

Selecttutti i dati da BusinessLineintmpBusLine funzionano bene.

select *
into tmpBusLine
from BusinessLine

Sto provando lo stesso, ma usando a stored procedure che restituisce dati non è esattamente lo stesso.

select *
into tmpBusLine
from
exec getBusinessLineHistory '16 Mar 2009'

Messaggio di uscita:

Messaggio 156, livello 15, stato 1, riga 2 Sintassi errata vicino alla parola chiave "exec".

Ho letto diversi esempi di creazione di una tabella temporanea con la stessa struttura della procedura memorizzata di output, che funziona bene, ma sarebbe bello non fornire colonne.


22
Con SELECT * INTO [TABLE NAME] conosci le colonne, poiché vengono copiate dalla tabella originale. Questo è esattamente quello che voglio se dovessi fare la stessa cosa contro una procedura memorizzata.
Ferdeen,


7
Voglio solo sottolineare che "select * in tmpBusLine" crea una tabella permanente. Probabilmente vuoi "selezionare * in #tmpBusLine". Sono sicuro che il poster originale lo abbia già scoperto, ma potrebbe aiutare gli altri a trovare questo post in quanto è il miglior risultato attualmente per la ricerca "seleziona nella tabella temporanea"
ktam33

2
Non so se questo è stato risolto o meno, ma il motivo per cui si ottiene l'errore è a causa della parola chiave from.
Wes Palmer,

9
Microsoft deve aggiungere SELECT * INTO FROM EXEC! Per favore!
kjmerf,

Risposte:


704

È possibile utilizzare OPENROWSET per questo. Dare un'occhiata. Ho anche incluso il codice sp_configure per abilitare le query distribuite ad hoc, nel caso in cui non sia già abilitato.

CREATE PROC getBusinessLineHistory
AS
BEGIN
    SELECT * FROM sys.databases
END
GO

sp_configure 'Show Advanced Options', 1
GO
RECONFIGURE
GO
sp_configure 'Ad Hoc Distributed Queries', 1
GO
RECONFIGURE
GO

SELECT * INTO #MyTempTable FROM OPENROWSET('SQLNCLI', 'Server=(local)\SQL2008;Trusted_Connection=yes;',
     'EXEC getBusinessLineHistory')

SELECT * FROM #MyTempTable

28
Questo è il modo giusto per farlo. OPENROWSET è praticamente l'unico modo per trattare i risultati di una procedura memorizzata come un'espressione di tabella.
Rob Farley,

37
Sembra un po 'ingombrante solo da inserire in una tabella. Molta configurazione da fare. Inoltre, quando l'ho provato ho ricevuto "Msg 7357, Level 16, State 2, Line 1 Impossibile elaborare l'oggetto" EXEC GetPartyAnalysisData 146 ". Il provider OLE DB" SQLNCLI "per il server collegato" (null) "indica che l'oggetto ha nessuna colonna o l'utente corrente non dispone delle autorizzazioni per quell'oggetto. " Quindi è necessario impostare un server collegato ...
Ferdeen,

10
Non è necessario un server collegato, ma è necessario ottenere la stringa di connessione corretta ... e inoltre, specificare il percorso completo della procedura memorizzata, incluso il nome del database e il proprietario dello sp.
Mart

18
eeeeew! un riferimento allo stesso server? cattiva. sicuramente più di un hack che dover creare manualmente la tabella temporanea
Tim Abell,

23
sono d'accordo che questo è un trucco e probabilmente dovrebbe essere evitato a meno che la tua schiena non sia contro il muro. Cambiare sp in una funzione è probabilmente un angolo migliore da prendere. A PARER MIO.
Greg

624

Se si desidera farlo senza prima dichiarare la tabella temporanea, è possibile provare a creare una funzione definita dall'utente anziché una procedura memorizzata e fare in modo che la funzione definita dall'utente restituisca una tabella. In alternativa, se si desidera utilizzare la procedura memorizzata, provare qualcosa del genere:

CREATE TABLE #tmpBus
(
   COL1 INT,
   COL2 INT
)

INSERT INTO #tmpBus
Exec SpGetRecords 'Params'

171
Penso che il punto fosse generare lo schema senza doverlo dichiarare esplicitamente.
Craig,

5
Sarei interessato a sapere qual è la differenza tra questa e la soluzione di @Aaron Alton sopra. Questo sembra molto più semplice, ma non sono sicuro di altre implicazioni.
funkymushroom,

11
Funzionerà, ma se si aggiungono ulteriori colonne alla procedura memorizzata SpGetRecords, ciò esploderà.
Brady Holt,

15
Ottieni solo un INSERT INTO EXEC per stack di chiamate. SpGetRecords e qualsiasi altro proc chiama non può usare questa strategia nel proprio codice. Questo può sorprendere i manutentori di SpGetRecords.
Matt Stephenson,

33
Questo non risponde affatto alla domanda e non vedo perché sia ​​così votato? L'OP ha dichiarato esplicitamente "senza definire [tabella temporanea]" e la tua prima riga ha un'istruzione create tabella temporanea.
NickG

296

In SQL Server 2005 è possibile utilizzare INSERT INTO ... EXECper inserire il risultato di una procedura memorizzata in una tabella. Dalla documentazione di MSDNINSERT (in effetti per SQL Server 2000):

--INSERT...EXECUTE procedure example
INSERT author_sales EXECUTE get_author_sales

122
Ciò richiede che gli autori di vendite siano definiti in anticipo. Sto cercando di evitarlo. Grazie.
Ferdeen,

5
Ho pensato tanto. Utile da inserire nelle tabelle tmp al volo, ma non così utile se è necessario conoscere la struttura del set di dati restituita da un proc memorizzato. Grazie per il tuo aiuto.
Ferdeen,


4
Per utilizzare lo stesso schema, è possibile effettuare una copia come segue: select top 0 * in TempTable da realTable ( stackoverflow.com/a/9206463/73794 )
Anche Mien

@EvenMien Mi sono momentaneamente emozionato quando ho visto il tuo commento ... ma purtroppo funziona solo se i risultati del tuo proc rispecchiano effettivamente un vero tavolo :(
BVernon

193

Questa è una risposta a una versione leggermente modificata della tua domanda. Se è possibile abbandonare l'uso di una procedura memorizzata per una funzione definita dall'utente, è possibile utilizzare una funzione definita dall'utente definita in tabella con valori di tabella. Questa è essenzialmente una procedura memorizzata (accetta parametri) che restituisce una tabella come set di risultati; e quindi andrà bene con una dichiarazione INTO.

Ecco un buon articolo rapido su di esso e altre funzioni definite dall'utente. Se hai ancora bisogno di guida per una procedura memorizzata, puoi avvolgere la funzione definita dall'utente definita in tabella con una procedura memorizzata. La procedura memorizzata passa i parametri quando chiama select * dalla funzione definita dall'utente definita in tabella con valori inline.

Ad esempio, avresti una funzione inline definita dall'utente definita da una tabella per ottenere un elenco di clienti per una particolare regione:

CREATE FUNCTION CustomersByRegion 
(  
    @RegionID int  
)
RETURNS TABLE 
AS
RETURN 
  SELECT *
  FROM customers
  WHERE RegionID = @RegionID
GO

È quindi possibile chiamare questa funzione per ottenere ciò che i risultati sono tali:

SELECT * FROM CustomersbyRegion(1)

O per fare un SELECT INTO:

SELECT * INTO CustList FROM CustomersbyRegion(1)

Se hai ancora bisogno di una procedura memorizzata, avvolgi la funzione come tale:

CREATE PROCEDURE uspCustomersByRegion 
(  
    @regionID int  
)
AS
BEGIN
     SELECT * FROM CustomersbyRegion(@regionID);
END
GO

Penso che questo sia il metodo più "privo di hack" per ottenere i risultati desiderati. Utilizza le funzionalità esistenti in quanto destinate ad essere utilizzate senza ulteriori complicazioni. Annidando la funzione inline definita dall'utente definita nella tabella nella procedura memorizzata, è possibile accedere alla funzionalità in due modi. Più! Hai solo un punto di manutenzione per il codice SQL effettivo.

È stato suggerito l'uso di OPENROWSET, ma non è per questo che la funzione OPENROWSET doveva essere utilizzata (da libri online):

Include tutte le informazioni di connessione necessarie per accedere ai dati remoti da un'origine dati OLE DB. Questo metodo è un'alternativa all'accesso alle tabelle in un server collegato ed è un metodo unico e ad hoc per la connessione e l'accesso ai dati remoti mediante OLE DB. Per riferimenti più frequenti alle origini dati OLE DB, utilizzare invece i server collegati.

L'uso di OPENROWSET porterà a termine il lavoro, ma comporterà un sovraccarico aggiuntivo per l'apertura delle connessioni locali e il marshalling dei dati. Inoltre, potrebbe non essere un'opzione in tutti i casi poiché richiede un'autorizzazione di query ad hoc che rappresenta un rischio per la sicurezza e pertanto potrebbe non essere desiderata. Inoltre, l'approccio OPENROWSET precluderà l'uso di stored procedure che restituiscono più di un set di risultati. L'avvolgimento di più funzioni definite dall'utente con valori di tabella incorporati in un'unica procedura memorizzata può ottenere questo risultato.


4
+1 Una funzione con valori di tabella è una soluzione appropriata. Dovremmo prendere nota degli svantaggi minori: la funzione con valori di tabella è un oggetto di database aggiuntivo e potrebbe essere necessario concederne i privilegi.
spencer7593,

2
Adoro la soluzione. Un piccolo inconveniente che ho colpito è che il mio tavolo non può essere ordinato in base a dove potrebbe averlo nella procedura memorizzata. Oh bene, lo sistemerò
sistemerò signor

5
Un altro problema: "Impossibile accedere alle tabelle temporanee dall'interno di una funzione"
mrwaim

7
La domanda originale è come creare una tabella temporanea con i risultati dello sp. Questo è un buon modello, ma non risponde a questa domanda
Greg

16
Greg, la prima riga nella mia risposta afferma "Questa è una risposta a una versione leggermente modificata della tua domanda." Il tuo commento è ridondante.
Christian Loris,

131
EXEC sp_serveroption 'YOURSERVERNAME', 'DATA ACCESS', TRUE

SELECT  *
INTO    #tmpTable
FROM    OPENQUERY(YOURSERVERNAME, 'EXEC db.schema.sproc 1')

2
Ottieni un "Messaggio 208, Livello 16, Stato 1, Riga 1 Nome oggetto non valido 'tmpBusLine' (probabilmente perché non definito in anticipo).
Ferdeen

1
@Ferds: scusa, all'inizio non ho capito la tua richiesta. Aggiornato con un'altra soluzione.
Quassnoi,

26
Ottima soluzione Un avvertimento, dovrai abilitare 'DATA ACCESS' sul tuo server: EXEC sp_serveroption 'TheServerName', 'DATA ACCESS', TRUE
jcollum il

8
Dovrai anche consentire l'accesso remoto al server. Ciò avrà conseguenze sulla sicurezza.
BraveNewMath,

7
Questo non funzionerà se la stored procedure di destinazione utilizza tabelle temporanee
Sal

125

La soluzione più semplice:

CREATE TABLE #temp (...);

INSERT INTO #temp
EXEC [sproc];

Se non conosci lo schema, puoi fare quanto segue. Si noti che questo metodo comporta gravi rischi per la sicurezza.

SELECT * 
INTO #temp
FROM OPENROWSET('SQLNCLI', 
                'Server=localhost;Trusted_Connection=yes;', 
                'EXEC [db].[schema].[sproc]')

se non conosco la colonna dei risultati restituiti allora ??? intendo colonna può variare. quindi come inserire il risultato nella tabella temporanea ???
SHEKHAR SHETE il

È possibile utilizzare OPENQUERY ma non è raccomandato poiché presenta difetti di sicurezza.
Tigerjz32

1
"se non conosco la colonna del set di risultati restituito, allora" non puoi usarlo nella tua logica. Come userete i dati se non sapete di cosa si tratta?
Adriaan Davel,

@AdriaanDavel Sono d'accordo con te sul fatto che dovresti sempre conoscere i tuoi dati (best practice), tuttavia ciò che potrebbe dire è che ci sono momenti in cui lo sproc restituisce colonne dinamiche e non sai sempre come sarà lo schema. In tal caso, è possibile utilizzare OPENROWSET per inserire e creare una tabella al volo. Tuttavia, ci sono evidenti rischi per la sicurezza nel fare questo ...
Tigerjz32,

1
@nurettin a volte non sai quale sarà la procedura memorizzata. Cosa succede in quel caso? Come è possibile creare una tabella temporanea (quando non si sa quale verrà restituita la procedura memorizzata) e inserirla in una procedura memorizzata?
Tigerjz32,

106

Quando la procedura memorizzata restituisce molte colonne e non si desidera "creare" manualmente una tabella temporanea per contenere il risultato, ho scoperto che il modo più semplice è passare alla procedura memorizzata e aggiungere una clausola "in" sulla ultima istruzione select e aggiungi 1 = 0 alla clausola where.

Eseguire una volta la procedura memorizzata e tornare indietro e rimuovere il codice SQL appena aggiunto. Ora avrai una tabella vuota corrispondente al risultato della procedura memorizzata. Puoi "tabella script come creare" per una tabella temporanea o semplicemente inserirla direttamente in quella tabella.


9
+1, suggerimento eccellente. Potresti anche aggiungere una variabile facoltativa rapida allo sproc chiamata @TableCreate o qualcosa di simile che quando non è null fai i passaggi precedenti. Non richiede la modifica dello sproc quindi una volta impostato.
Ian Roke,

1
@dotjoe Crea SELECT INTOuna tabella temporanea e crea una tabella di script come crearla dalla tabella temporanea? Le tabelle temporanee vengono visualizzate tempdbma non riesco a fare clic con il pulsante destro del mouse e creare uno script. Qualsiasi aiuto è apprezzato.
DotnetDude,

2
@DotNetDude è possibile select ... into new_tablecreare implicitamente una tabella effettiva.
dotjoe,

Quindi prendi la definizione di colonna approssimativa dallo schema di tabella vuoto; sostituisci "..." alla fine con declare @s varchar(max)='';select @s=@s+','+COLUMN_NAME+' '+DATA_TYPE+isnull('('+case CHARACTER_MAXIMUM_LENGTH when -1 then 'max' else cast(CHARACTER_MAXIMUM_LENGTH as varchar(10))end+')','')from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='...';select @s
TABLE_NAME

Questa è la soluzione migliore!
Lucas925,

66
declare @temp table
(
    name varchar(255),
    field varchar(255),
    filename varchar(255),
    filegroup varchar(255),
    size varchar(255),
    maxsize varchar(255),
    growth varchar(255),
    usage varchar(255)
);
INSERT @temp  Exec sp_helpfile;
select * from @temp;

3
non affronta la domanda originale OP, eseguendo l'inserimento senza definire prima la tabella temporanea.
martedì

48

La procedura memorizzata recupera solo i dati o li modifica? Se viene utilizzato solo per il recupero, è possibile convertire la procedura memorizzata in una funzione e utilizzare le espressioni di tabella comuni (CTE) senza doverlo dichiarare, come segue:

with temp as (
    select * from dbo.fnFunctionName(10, 20)
)
select col1, col2 from temp

Tuttavia, tutto ciò che deve essere recuperato dal CTE deve essere utilizzato in una sola istruzione. Non puoi fare unwith temp as ... e provare a usarlo dopo un paio di righe di SQL. È possibile avere più CTE in un'istruzione per query più complesse.

Per esempio,

with temp1020 as (
    select id from dbo.fnFunctionName(10, 20)
),
temp2030 as (
    select id from dbo.fnFunctionName(20, 30)
)
select * from temp1020 
where id not in (select id from temp2030)

1
Queste non sono tabelle temporanee, sono CTE. technet.microsoft.com/en-us/library/…
yucer

5
Grazie @yucer ... Credo di non sapere che all'epoca erano chiamati CTE :)
SO User

48

Se la tabella dei risultati del tuo proc memorizzato è troppo complicata per scrivere manualmente l'istruzione "create table" e non puoi usare OPENQUERY O OPENROWSET, puoi usare sp_help per generare per te l'elenco di colonne e tipi di dati. Una volta che hai l'elenco delle colonne, è solo una questione di formattazione per soddisfare le tue esigenze.

Passaggio 1: Aggiungi "in #temp" alla query di output (ad esempio "seleziona [...] in #temp da [...]").

Il modo più semplice è modificare direttamente la query di output nel proc. se non è possibile modificare il proc memorizzato, è possibile copiare il contenuto in una nuova finestra della query e modificare la query lì.

Passaggio 2: eseguire sp_help sulla tabella temporanea. (ad es. "exec tempdb..sp_help #temp")

Dopo aver creato la tabella temporanea, eseguire sp_help sulla tabella temporanea per ottenere un elenco delle colonne e dei tipi di dati inclusa la dimensione dei campi varchar.

Passaggio 3: copiare le colonne e i tipi di dati in un'istruzione create table

Ho un foglio Excel che utilizzo per formattare l'output di sp_help in un'istruzione "crea tabella". Non hai bisogno di nulla di speciale, basta copiare e incollare nel tuo editor SQL. Utilizzare i nomi, le dimensioni e i tipi di colonna per costruire un'istruzione "Crea tabella #x [...]" o "declare @x tabella [...]" che è possibile utilizzare per INSERIRE i risultati della procedura memorizzata.

Passaggio 4: inserire nella tabella appena creata

Ora avrai una query simile alle altre soluzioni descritte in questo thread.

DECLARE @t TABLE 
(
   --these columns were copied from sp_help
   COL1 INT,
   COL2 INT   
)

INSERT INTO @t 
Exec spMyProc 

Questa tecnica può anche essere utilizzata per convertire una tabella temporanea ( #temp) in una variabile di tabella ( @temp). Sebbene ciò possa comportare più passaggi rispetto alla semplice scrittura create tabledell'istruzione, impedisce errori manuali come errori di battitura e discrepanze tra tipi di dati in processi di grandi dimensioni. Il debug di un refuso può richiedere più tempo rispetto alla scrittura della query.


37

Se OPENROWSET ti sta causando problemi, c'è un altro modo dal 2012 in poi; utilizzare sys.dm_exec_describe_first_result_set_for_object, come menzionato qui: recuperare i nomi delle colonne e i tipi di una procedura memorizzata?

Innanzitutto, creare questa procedura memorizzata per generare l'SQL per la tabella temporanea:

CREATE PROCEDURE dbo.usp_GetStoredProcTableDefinition(
    @ProcedureName  nvarchar(128),
    @TableName      nvarchar(128),
    @SQL            nvarchar(max) OUTPUT
)
AS
SET @SQL = 'CREATE TABLE ' + @tableName + ' ('

SELECT @SQL = @SQL + '['+name +'] '+ system_type_name +''  + ','
        FROM sys.dm_exec_describe_first_result_set_for_object
        (
          OBJECT_ID(@ProcedureName), 
          NULL
        );

--Remove trailing comma
SET @SQL = SUBSTRING(@SQL,0,LEN(@SQL))    
SET @SQL =  @SQL +')'

Per utilizzare la procedura, chiamarla nel modo seguente:

DECLARE     @SQL    NVARCHAR(MAX)

exec dbo.usp_GetStoredProcTableDefinition
    @ProcedureName='dbo.usp_YourProcedure',
    @TableName='##YourGlobalTempTable',@SQL = @SQL OUTPUT

INSERT INTO ##YourGlobalTempTable
EXEC    [dbo].usp_YourProcedure

select * from ##YourGlobalTempTable

Nota che sto usando una tabella temporanea globale. Questo perché l'utilizzo di EXEC per eseguire l'SQL dinamico crea una propria sessione, pertanto una normale tabella temporanea non rientra nell'ambito di alcun codice successivo. Se una tabella temporanea globale è un problema, è possibile utilizzare una tabella temporanea ordinaria, ma ogni SQL successivo dovrebbe essere dinamico, ovvero eseguito anche dall'istruzione EXEC.


4
Hai dimenticato di creare la tabella da @SQL.
Trisped il

32

Quassnoi mi ha messo quasi tutto lì, ma mancava una cosa:

**** Avevo bisogno di usare i parametri nella procedura memorizzata. ****

E OPENQUERY non consente che ciò accada:

Quindi ho trovato un modo di lavorare con il sistema e anche di non dover rendere la definizione della tabella così rigida e ridefinirla all'interno di un'altra procedura memorizzata (e ovviamente cogliere l'occasione che potrebbe non funzionare)!

Sì, è possibile creare dinamicamente la definizione di tabella restituita dalla procedura memorizzata utilizzando l'istruzione OPENQUERY con variabili false (purché NO SET DI RISULTATI restituisca lo stesso numero di campi e nella stessa posizione di un set di dati con dati validi).

Una volta creata la tabella, è possibile utilizzare la stored procedure exec nella tabella temporanea per tutto il giorno.


E per notare (come indicato sopra) è necessario abilitare l'accesso ai dati,

EXEC sp_serveroption 'MYSERVERNAME', 'DATA ACCESS', TRUE

Codice:

declare @locCompanyId varchar(8)
declare @locDateOne datetime
declare @locDateTwo datetime

set @locDateOne = '2/11/2010'
set @locDateTwo = getdate()

--Build temporary table (based on bogus variable values)
--because we just want the table definition and
--since openquery does not allow variable definitions...
--I am going to use bogus variables to get the table defintion.

select * into #tempCoAttendanceRpt20100211
FROM OPENQUERY(DBASESERVER,
  'EXEC DATABASE.dbo.Proc_MyStoredProc 1,"2/1/2010","2/15/2010 3:00 pm"')

set @locCompanyId = '7753231'

insert into #tempCoAttendanceRpt20100211
EXEC DATABASE.dbo.Proc_MyStoredProc @locCompanyId,@locDateOne,@locDateTwo

set @locCompanyId = '9872231'

insert into #tempCoAttendanceRpt20100211
EXEC DATABASE.dbo.Proc_MyStoredProc @locCompanyId,@locDateOne,@locDateTwo

select * from #tempCoAttendanceRpt20100211
drop table #tempCoAttendanceRpt20100211

Grazie per le informazioni fornite originariamente ... Sì, finalmente non devo creare tutte queste definizioni di tabelle fasulle (rigorose) quando si usano i dati da un'altra procedura memorizzata o database, e è possibile utilizzare anche i parametri.

Cerca tag di riferimento:

  • SQL 2005 stored procedure nella tabella temporanea

  • openquery con stored procedure e variabili 2005

  • openquery con variabili

  • eseguire la stored procedure nella tabella temporanea

Aggiornamento: questo non funzionerà con le tabelle temporanee, quindi ho dovuto ricorrere alla creazione manuale della tabella temporanea.

Avviso scadente : questo non funzionerà con le tabelle temporanee , http://www.sommarskog.se/share_data.html#OPENQUERY

Riferimento: la prossima cosa è definire LOCALSERVER. Potrebbe sembrare una parola chiave nell'esempio, ma in realtà è solo un nome. Ecco come lo fai:

sp_addlinkedserver @server = 'LOCALSERVER',  @srvproduct = '',
                   @provider = 'SQLOLEDB', @datasrc = @@servername

Per creare un server collegato, è necessario disporre dell'autorizzazione ALTER ANY SERVER o essere membro di uno dei ruoli fissi del server sysadmin o setupadmin.

OPENQUERY apre una nuova connessione a SQL Server. Ciò ha alcune implicazioni:

La procedura chiamata con OPENQUERY non può fare riferimento a tabelle temporanee create nella connessione corrente.

La nuova connessione ha il proprio database predefinito (definito con sp_addlinkedserver, il valore predefinito è master), quindi tutte le specifiche dell'oggetto devono includere un nome di database.

Se hai una transazione aperta e stai trattenendo i blocchi quando chiami OPENQUERY, la procedura chiamata non può accedere a ciò che blocchi. Cioè, se non stai attento, ti bloccherai.

La connessione non è gratuita, quindi c'è una penalità per le prestazioni.


1
Se non conosci il nome del tuo server, utilizza SELECT @@SERVERNAME. Puoi anche usareEXEC sp_serveroption @@SERVERNAME, 'DATA ACCESS', TRUE
Contango

24

Se sei abbastanza fortunato da avere SQL 2012 o versioni successive, puoi usare dm_exec_describe_first_result_set_for_object

Ho appena modificato il sql fornito da gotqn. Grazie gotqn.

Ciò crea una tabella temporanea globale con il nome uguale al nome della procedura. La tabella temporanea può essere successivamente utilizzata come richiesto. Basta non dimenticare di lasciarlo cadere prima di rieseguire.

    declare @procname nvarchar(255) = 'myProcedure',
            @sql nvarchar(max) 

    set @sql = 'create table ##' + @procname + ' ('
    begin
            select      @sql = @sql + '[' + r.name + '] ' +  r.system_type_name + ','
            from        sys.procedures AS p
            cross apply sys.dm_exec_describe_first_result_set_for_object(p.object_id, 0) AS r
            where       p.name = @procname

            set @sql = substring(@sql,1,len(@sql)-1) + ')'
            execute (@sql)
            execute('insert ##' + @procname + ' exec ' + @procname)
    end

1
Eccellente! Solo un'osservazione: utilizzare sys.all_objectsinvece di sys.proceduresse si desidera eseguire questa operazione per le stored procedure integrate.
Gert Arnold,

2
Ciò fallirà anche se SP utilizza tabelle temporanee al suo interno. (ma è abbastanza utile avere questo come proc nel tuo arsenale)
Trubs

23

Questo proc memorizzato fa il lavoro:

CREATE PROCEDURE [dbo].[ExecIntoTable]
(
    @tableName          NVARCHAR(256),
    @storedProcWithParameters   NVARCHAR(MAX)
)
AS
BEGIN
    DECLARE @driver         VARCHAR(10)
    DECLARE @connectionString   NVARCHAR(600)
    DECLARE @sql            NVARCHAR(MAX)
    DECLARE @rowsetSql      NVARCHAR(MAX)

    SET @driver = '''SQLNCLI'''

    SET @connectionString = 
        '''server=' + 
            CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(256)) + 
            COALESCE('\' + CAST(SERVERPROPERTY('InstanceName') AS NVARCHAR(256)), '') + 
        ';trusted_connection=yes'''

    SET @rowsetSql = '''EXEC ' + REPLACE(@storedProcWithParameters, '''', '''''') + ''''

    SET @sql = '
SELECT
    *
INTO 
    ' + @tableName + ' 
FROM
    OPENROWSET(' + @driver + ',' + @connectionString + ',' + @rowsetSql + ')'

    EXEC (@sql)
END
GO

È una leggera rielaborazione di questo: inserisci i risultati della procedura memorizzata nella tabella in modo che funzioni effettivamente.

Se vuoi che funzioni con una tabella temporanea, dovrai utilizzare una ##GLOBALtabella e rilasciarla in seguito.


17

Per inserire il primo set di record di una procedura memorizzata in una tabella temporanea, è necessario conoscere quanto segue:

  1. solo la prima riga della procedura memorizzata può essere inserita in una tabella temporanea
  2. la procedura memorizzata non deve eseguire l'istruzione T-SQL dinamica ( sp_executesql)
  3. devi prima definire la struttura della tabella temporanea

Quanto sopra può sembrare un limite, ma IMHO ha perfettamente senso: se stai usando sp_executesqlpuoi restituire due colonne e una volta dieci, e se hai più set di risultati, non puoi inserirli anche in più tabelle - puoi inserire il massimo in due tabelle in un'istruzione T-SQL (usandoOUTPUT clausola e nessun trigger).

Quindi, il problema è principalmente come definire la struttura della tabella temporanea prima di eseguire l' EXEC ... INTO ...istruzione.

Il primo funziona con OBJECT_IDmentre il secondo e il terzo funzionano anche con query ad hoc. Preferisco usare DMV invece di sp in quanto è possibile utilizzare CROSS APPLYe creare definizioni di tabelle temporanee per più procedure contemporaneamente.

SELECT p.name, r.* 
FROM sys.procedures AS p
CROSS APPLY sys.dm_exec_describe_first_result_set_for_object(p.object_id, 0) AS r;

Inoltre, presta attenzione al system_type_namecampo in quanto può essere molto utile. Memorizza la definizione completa della colonna. Per esempio:

smalldatetime
nvarchar(max)
uniqueidentifier
nvarchar(1000)
real
smalldatetime
decimal(18,2)

e puoi usarlo direttamente nella maggior parte dei casi per creare la definizione di tabella.

Quindi, penso che nella maggior parte dei casi (se la procedura memorizzata soddisfa determinati criteri) è possibile creare facilmente istruzioni dinamiche per risolvere tali problemi (creare la tabella temporanea, inserire il risultato della procedura memorizzata, fare ciò che è necessario con i dati) .


Si noti che gli oggetti sopra non riescono a definire i dati del primo set di risultati in alcuni casi, ad esempio quando vengono eseguite istruzioni T-SQL dinamiche o vengono utilizzate tabelle temporanee nella procedura memorizzata.


osservazione pratica sulle limitazioni: se devi inserire l'output di alcuni sp (chiamiamolo SP_LEVEL_0) nella tabella temporanea creata dinamicamente usando l'approccio sopra in un altro sp (chiamiamolo SP_LEVEL_1), non puoi fare lo stesso trucco per l'output di questo SP_LEVEL_1 un'altra tabella temporanea in SP_LEVEL_2
nahab

17
  1. Sto creando una tabella con i seguenti schemi e dati.
  2. Creare una procedura memorizzata.
  3. Ora so qual è il risultato della mia procedura, quindi sto eseguendo la seguente query.

    CREATE TABLE [dbo].[tblTestingTree](
        [Id] [int] IDENTITY(1,1) NOT NULL,
        [ParentId] [int] NULL,
        [IsLeft] [bit] NULL,
        [IsRight] [bit] NULL,
    CONSTRAINT [PK_tblTestingTree] PRIMARY KEY CLUSTERED
    (
        [Id] ASC
    ) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO
    SET IDENTITY_INSERT [dbo].[tblTestingTree] ON
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (1, NULL, NULL, NULL)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (2, 1, 1, NULL)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (3, 1, NULL, 1)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (4, 2, 1, NULL)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (5, 2, NULL, 1)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (6, 3, 1, NULL)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (7, 3, NULL, 1)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (8, 4, 1, NULL)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (9, 4, NULL, 1)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (10, 5, 1, NULL)
    
    SET IDENTITY_INSERT [dbo].[tblTestingTree] OFF

    VALUES (10, 5, 1, NULL) SET IDENTITY_INSERT [dbo]. [TblTestingTree] Attivo

    create procedure GetDate
    as
    begin
        select Id,ParentId from tblTestingTree
    end
    
    create table tbltemp
    (
        id int,
        ParentId int
    )
    insert into tbltemp
    exec GetDate
    
    select * from tbltemp;

15

Se la query non contiene parametri, utilizzare OpenQueryelse use OpenRowset.

La cosa di base sarebbe creare lo schema secondo la procedura memorizzata e inserirlo in quella tabella. per esempio:

DECLARE @abc TABLE(
                  RequisitionTypeSourceTypeID INT
                , RequisitionTypeID INT
                , RequisitionSourcingTypeID INT
                , AutoDistOverride INT
                , AllowManagerToWithdrawDistributedReq INT
                , ResumeRequired INT
                , WarnSupplierOnDNRReqSubmission  INT
                , MSPApprovalReqd INT
                , EnableMSPSupplierCounterOffer INT
                , RequireVendorToAcceptOffer INT
                , UseCertification INT
                , UseCompetency INT
                , RequireRequisitionTemplate INT
                , CreatedByID INT
                , CreatedDate DATE
                , ModifiedByID INT
                , ModifiedDate DATE
                , UseCandidateScheduledHours INT
                , WeekEndingDayOfWeekID INT
                , AllowAutoEnroll INT
                )
INSERT INTO @abc
EXEC [dbo].[usp_MySp] 726,3
SELECT * FROM @abc

13

Codice

CREATE TABLE #T1
(
    col1 INT NOT NULL,
    col2 NCHAR(50) NOT NULL,
    col3 TEXT NOT NULL,
    col4 DATETIME NULL,
    col5 NCHAR(50) NULL,
    col6 CHAR(2) NULL,
    col6 NCHAR(100) NULL,
    col7 INT NULL,
    col8 NCHAR(50) NULL,
    col9 DATETIME NULL,
    col10 DATETIME NULL
)

DECLARE @Para1 int
DECLARE @Para2 varchar(32)
DECLARE @Para3 varchar(100)
DECLARE @Para4 varchar(15)
DECLARE @Para5 varchar (12)
DECLARE @Para6 varchar(1)
DECLARE @Para7 varchar(1)


SET @Para1 = 1025
SET @Para2 = N'6as54fsd56f46sd4f65sd'
SET @Para3 = N'XXXX\UserName'
SET @Para4 = N'127.0.0.1'
SET @Para5 = N'XXXXXXX'
SET @Para6 = N'X'
SET @Para7 = N'X'

INSERT INTO #T1
(
    col1,
    col2,
    col3,
    col4,
    col5,
    col6,
    col6,
    col7,
    col8,
    col9,
    col10,
)
EXEC [dbo].[usp_ProcedureName] @Para1, @Para2, @Para3, @Para4, @Para5, @Para6, @Para6

Spero che questo possa essere d'aiuto. Si prega di qualificarsi come appropriato.


11

Ho trovato il passaggio di array / DataTable in Stored procedure che potrebbero darti un'altra idea su come potresti andare a risolvere il tuo problema.

Il collegamento suggerisce di utilizzare un parametro di tipo Immagine per passare alla procedura memorizzata. Quindi nella procedura memorizzata, l'immagine viene trasformata in una variabile di tabella contenente i dati originali.

Forse esiste un modo per usarlo con una tabella temporanea.


4
Ciò non è più necessario nelle versioni Sql2008 e successive con l'introduzione dei parametri del valore della tabella . Ora è possibile passare direttamente un set di dati .net o un oggetto datatable a una stored procedure sql con la necessità di eseguire la conversione in byte come indicato nel link sopra
EndlessSpace

10

Ho incontrato lo stesso problema ed ecco cosa ho fatto per questo dal suggerimento di Paul . La parte principale è qui da usare NEWID()per evitare che più utenti eseguano le procedure / gli script del negozio allo stesso tempo, il dolore per la tabella temporanea globale.

DECLARE @sql varchar(max) = '', 
@tmp_global_table varchar(255) = '##global_tmp_' + CONVERT(varchar(36), NEWID())
SET @sql = @sql + 'select * into [' + @tmp_global_table + '] from YOURTABLE'
EXEC(@sql)

EXEC('SELECT * FROM [' + @tmp_global_table + ']')

9

Un altro metodo è quello di creare un tipo e utilizzare PIPELINED per poi restituire l'oggetto. Questo è limitato alla conoscenza delle colonne comunque. Ma ha il vantaggio di poter fare:

SELECT * 
FROM TABLE(CAST(f$my_functions('8028767') AS my_tab_type))

Cos'è questo? Non sembra avere nulla a che fare con SQL Server di cui tratta questa domanda
Martin Smith,

8

È un semplice processo in 2 passaggi: - crea una tabella temporanea - Inserisci nella tabella temporanea.

Codice per eseguire lo stesso:

CREATE TABLE #tempTable (Column1 int, Column2 varchar(max));
INSERT INTO #tempTable 
EXEC [app].[Sproc_name]
@param1 = 1,
@param2 =2;

downvoted; molto simile alle risposte esistenti.
iokevins,

6

Dopo aver cercato, ho trovato un modo per creare una tabella temporanea in modo dinamico per qualsiasi procedura memorizzata senza utilizzare OPENROWSETo OPENQUERYutilizzare uno schema generico della definizione dei risultati della Stored Procedure, specialmente quando non si è amministratori del database.

Il server SQL ha un proc integrato sp_describe_first_result_setche può fornire lo schema di qualsiasi set di risultati delle procedure. Ho creato una tabella dello schema dai risultati di questa procedura e ho impostato manualmente tutto il campo su NULLABLE.

declare @procname varchar(100) = 'PROCEDURENAME' -- your procedure name
declare @param varchar(max) = '''2019-06-06''' -- your parameters 
declare @execstr nvarchar(max) = N'exec ' + @procname
declare @qry nvarchar(max)

-- Schema table to store the result from sp_describe_first_result_set.
create table #d
(is_hidden  bit  NULL, column_ordinal   int  NULL, name sysname NULL, is_nullable   bit  NULL, system_type_id   int  NULL, system_type_name nvarchar(256) NULL,
max_length  smallint  NULL, precision   tinyint  NULL,  scale   tinyint  NULL,  collation_name  sysname NULL, user_type_id  int NULL, user_type_database    sysname NULL,
user_type_schema    sysname NULL,user_type_name sysname NULL,assembly_qualified_type_name   nvarchar(4000),xml_collection_id    int NULL,xml_collection_database    sysname NULL,
xml_collection_schema   sysname NULL,xml_collection_name    sysname NULL,is_xml_document    bit  NULL,is_case_sensitive bit  NULL,is_fixed_length_clr_type  bit  NULL,
source_server   sysname NULL,source_database    sysname NULL,source_schema  sysname NULL,source_table   sysname NULL,source_column  sysname NULL,is_identity_column bit NULL,
is_part_of_unique_key   bit NULL,is_updateable  bit NULL,is_computed_column bit NULL,is_sparse_column_set   bit NULL,ordinal_in_order_by_list   smallint NULL,
order_by_list_length    smallint NULL,order_by_is_descending    smallint NULL,tds_type_id   int  NULL,tds_length    int  NULL,tds_collation_id  int NULL,
tds_collation_sort_id   tinyint NULL)


-- Get result set definition of your procedure
insert into #d
EXEC sp_describe_first_result_set @exestr, NULL, 0

-- Create a query to generate and populate a global temp table from above results
select 
@qry = 'Create table ##t(' +
stuff(  
    (select ',' + name + ' '+ system_type_name + ' NULL'
    from #d d For XML Path, TYPE)
    .value(N'.[1]', N'nvarchar(max)')
, 1,1,'')
+ ')

insert into ##t 
Exec '+@procname+' ' + @param

Exec sp_executesql @qry

-- Use below global temp table to query the data as you may
select * from ##t

-- **WARNING** Don't forget to drop the global temp table ##t.
--drop table ##t
drop table #d 

Sviluppato e testato sulla versione SQL Server - Microsoft SQL Server 2016 (RTM) - 13.0.1601.5 (Build 17134 :)

È possibile modificare lo schema per la versione del server SQL che si sta utilizzando (se necessario).


4

Se si conoscono i parametri che vengono passati e se non si ha accesso a make sp_configure, modificare la procedura memorizzata con questi parametri e gli stessi possono essere memorizzati in una tabella globale ##.


3

Questo può essere fatto in SQL Server 2014+ purché la procedura memorizzata restituisca solo una tabella. Se qualcuno trova un modo per farlo per più tavoli, mi piacerebbe saperlo.

DECLARE @storedProcname NVARCHAR(MAX) = ''
SET @storedProcname = 'myStoredProc'

DECLARE @strSQL AS VARCHAR(MAX) = 'CREATE TABLE myTableName '

SELECT @strSQL = @strSQL+STUFF((
SELECT ',' +name+' ' + system_type_name 
FROM sys.dm_exec_describe_first_result_set_for_object (OBJECT_ID(@storedProcname),0)
FOR XML PATH('')
),1,1,'(') + ')'

EXEC (@strSQL)

INSERT INTO myTableName

EXEC ('myStoredProc @param1=1, @param2=2')

SELECT * FROM myTableName

DROP TABLE myTableName

Ciò estrae la definizione della tabella restituita dalle tabelle di sistema e la utilizza per creare la tabella temporanea. È quindi possibile popolarlo dalla procedura memorizzata come indicato in precedenza.

Ci sono anche varianti di questo che funzionano anche con Dynamic SQL.


2

Qualche anno in ritardo alla domanda, ma avevo bisogno di qualcosa del genere per una generazione di codice veloce e sporca. Credo che, come altri hanno affermato, è più semplice definire la tabella temporanea in anticipo, ma questo metodo dovrebbe funzionare per semplici query su procedure memorizzate o istruzioni sql.

Questo sarà un po 'contorto, ma prende in prestito dai contributori qui e dalla soluzione di Paul White da DBA Stack Exchange Ottieni i tipi di colonna dei risultati della procedura memorizzata . Ancora una volta, ribadire questo approccio ed esempio non è progettato per i processi in un ambiente multiutente. In questo caso, la definizione della tabella viene impostata per un breve periodo in una tabella temporanea globale per riferimento mediante un processo modello di generazione del codice.

Non l'ho ancora testato completamente, quindi potrebbero esserci delle avvertenze, quindi potresti voler andare al collegamento MSDN nella risposta di Paul White. Questo vale per SQL 2012 e versioni successive.

Innanzitutto utilizzare la procedura memorizzata sp_describe_first_result_set che assomiglia alla descrizione di Oracle.

Ciò valuterà la prima riga del primo set di risultati, quindi se la procedura o l'istruzione memorizzata restituisce più query descriverà solo il primo risultato.

Ho creato un proc memorizzato per suddividere le attività che restituiscono un singolo campo da cui selezionare per creare la definizione della tabella temporanea.

CREATE OR ALTER PROCEDURE [dbo].[sp_GetTableDefinitionFromSqlBatch_DescribeFirstResultSet]
(
     @sql NVARCHAR(4000)
    ,@table_name VARCHAR(100)
    ,@TableDefinition NVARCHAR(MAX) OUTPUT
)
AS
BEGIN
    SET NOCOUNT ON
    DECLARE @TempTableDefinition NVARCHAR(MAX)
    DECLARE @NewLine NVARCHAR(4) = CHAR(13)+CHAR(10)

    DECLARE @ResultDefinition TABLE (  --The View Definition per MSDN
      is_hidden         bit NOT NULL
    , column_ordinal    int NOT NULL
    , [name]            sysname NULL
    , is_nullable       bit NOT NULL
    , system_type_id    int NOT NULL
    , system_type_name  nvarchar(256) NULL
    , max_length        smallint NOT NULL
    , [precision]       tinyint NOT NULL
    , scale             tinyint NOT NULL
    , collation_name    sysname NULL    
    , user_type_id      int NULL
    , user_type_database    sysname NULL    
    , user_type_schema  sysname NULL
    , user_type_name    sysname NULL    
    , assembly_qualified_type_name      nvarchar(4000)  
    , xml_collection_id         int NULL
    , xml_collection_database   sysname NULL    
    , xml_collection_schema     sysname NULL    
    , xml_collection_name       sysname NULL
    , is_xml_document           bit NOT NULL            
    , is_case_sensitive         bit NOT NULL            
    , is_fixed_length_clr_type  bit NOT NULL    
    , source_server             sysname NULL            
    , source_database           sysname NULL
    , source_schema             sysname NULL
    , source_table              sysname NULL
    , source_column             sysname NULL
    , is_identity_column        bit NULL
    , is_part_of_unique_key     bit NULL
    , is_updateable             bit NULL
    , is_computed_column        bit NULL
    , is_sparse_column_set      bit NULL
    , ordinal_in_order_by_list  smallint NULL   
    , order_by_is_descending    smallint NULL   
    , order_by_list_length      smallint NULL
    , tds_type_id               int NOT NULL
    , tds_length                int NOT NULL
    , tds_collation_id          int NULL
    , tds_collation_sort_id     tinyint NULL
    )

    --Insert the description into table variable    
    INSERT @ResultDefinition
    EXEC sp_describe_first_result_set @sql

    --Now Build the string to create the table via union select statement
    ;WITH STMT AS (
        SELECT N'CREATE TABLE ' + @table_name + N' (' AS TextVal
        UNION ALL

        SELECT 
         CONCAT(
                CASE column_ordinal
                    WHEN 1 THEN '     ' ELSE '   , ' END  --Determines if comma should precede
                , QUOTENAME([name]) , '   ', system_type_name  -- Column Name and SQL TYPE
                ,CASE is_nullable 
                    WHEN 0 THEN '   NOT NULL' ELSE '   NULL' END --NULLABLE CONSTRAINT          
               ) AS TextVal
        FROM @ResultDefinition WHERE is_hidden = 0  -- May not be needed
        UNION ALL

        SELECT N');' + @NewLine
    ) 

    --Now Combine the rows to a single String
    SELECT @TempTableDefinition = COALESCE (@TempTableDefinition + @NewLine + TextVal, TextVal) FROM STMT

    SELECT @TableDefinition = @TempTableDefinition
END

L'enigma è che devi usare una tabella globale, ma devi renderla abbastanza unica in modo da poterla abbandonare e creare da essa frequentemente senza preoccuparti di una collisione.
Nell'esempio ho usato un Guid (FE264BF5_9C32_438F_8462_8A5DC8DEE49E) per la variabile globale che sostituisce i trattini con trattino basso

DECLARE @sql NVARCHAR(4000) = N'SELECT @@SERVERNAME as ServerName, GETDATE() AS Today;'
DECLARE @GlobalTempTable VARCHAR(100) = N'##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable'

--@sql can be a stored procedure name like dbo.foo without parameters

DECLARE @TableDef NVARCHAR(MAX)

DROP TABLE IF EXISTS #MyTempTable
DROP TABLE IF EXISTS ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable

EXEC [dbo].[sp_GetTableDefinitionFromSqlBatch_DescribeFirstResultSet] 
    @sql, @GlobalTempTable, @TableDef OUTPUT

--Creates the global table ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable
EXEC sp_executesql @TableDef 

--Now Call the stored procedure, SQL Statement with Params etc.
INSERT ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable
    EXEC sp_executesql @sql 

--Select the results into your undefined Temp Table from the Global Table
SELECT * 
INTO #MyTempTable
FROM ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable

SELECT * FROM #MyTempTable

DROP TABLE IF EXISTS #MyTempTable
DROP TABLE IF EXISTS ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable

Ancora una volta, l'ho testato solo con semplici query di stored procedure e semplici query in modo che il tuo chilometraggio possa variare. Spero che questo aiuti qualcuno.


1

Bene, devi creare una tabella temporanea, ma non deve avere lo schema giusto .... Ho creato una procedura memorizzata che modifica una tabella temporanea esistente in modo che abbia le colonne richieste con i dati giusti digitare e ordinare (eliminando tutte le colonne esistenti, aggiungendo nuove colonne):

GO
create procedure #TempTableForSP(@tableId int, @procedureId int)  
as   
begin  
    declare @tableName varchar(max) =  (select name  
                                        from tempdb.sys.tables 
                                        where object_id = @tableId
                                        );    
    declare @tsql nvarchar(max);    
    declare @tempId nvarchar(max) = newid();      
    set @tsql = '    
    declare @drop nvarchar(max) = (select  ''alter table tempdb.dbo.' + @tableName 
            +  ' drop column ''  + quotename(c.name) + '';''+ char(10)  
                                   from tempdb.sys.columns c   
                                   where c.object_id =  ' + 
                                         cast(@tableId as varchar(max)) + '  
                                   for xml path('''')  
                                  )    
    alter table tempdb.dbo.' + @tableName + ' add ' + QUOTENAME(@tempId) + ' int;
    exec sp_executeSQL @drop;    
    declare @add nvarchar(max) = (    
                                select ''alter table ' + @tableName 
                                      + ' add '' + name 
                                      + '' '' + system_type_name 
                           + case when d.is_nullable=1 then '' null '' else '''' end 
                                      + char(10)   
                              from sys.dm_exec_describe_first_result_set_for_object(' 
                               + cast(@procedureId as varchar(max)) + ', 0) d  
                                order by column_ordinal  
                                for xml path(''''))    

    execute sp_executeSQL  @add;    
    alter table '  + @tableName + ' drop column ' + quotename(@tempId) + '  ';      
    execute sp_executeSQL @tsql;  
end         
GO

create table #exampleTable (pk int);

declare @tableId int = object_Id('tempdb..#exampleTable')
declare @procedureId int = object_id('examplestoredProcedure')

exec #TempTableForSP @tableId, @procedureId;

insert into #exampleTable
exec examplestoredProcedure

Nota che non funzionerà se sys.dm_exec_describe_first_result_set_for_object non è in grado di determinare i risultati della procedura memorizzata (ad esempio se utilizza una tabella temporanea).


0

Se si consente a SQL dinamico di creare una tabella temporanea, questa tabella appartiene alla connessione SQL dinamica, al contrario della connessione da cui viene chiamata la procedura memorizzata.

DECLARE @COMMA_SEPARATED_KEYS varchar(MAX);
DROP TABLE IF EXISTS KV;
CREATE TABLE KV (id_person int, mykey varchar(30), myvalue int);
INSERT INTO KV VALUES
(1, 'age', 16),
(1, 'weight', 63),
(1, 'height', 175),
(2, 'age', 26),
(2, 'weight', 83),
(2, 'height', 185);
WITH cte(mykey) AS (
    SELECT DISTINCT mykey FROM KV
) 
SELECT @COMMA_SEPARATED_KEYS=STRING_AGG(mykey,',') FROM cte;
SELECT @COMMA_SEPARATED_KEYS AS keys;

inserisci qui la descrizione dell'immagine

DECLARE @ExecuteExpression varchar(MAX);

DROP TABLE IF EXISTS #Pivoted;

SET @ExecuteExpression = N'
SELECT * 
INTO #Pivoted
FROM
(
    SELECT
        mykey,
        myvalue,
        id_person
    FROM KV
) AS t
PIVOT(
    MAX(t.myvalue) 
    FOR mykey IN (COMMA_SEPARATED_KEYS)
) AS pivot_table;
';

SET @ExecuteExpression = REPLACE(@ExecuteExpression, 'COMMA_SEPARATED_KEYS', @COMMA_SEPARATED_KEYS);

EXEC(@ExecuteExpression);

SELECT * FROM #Pivoted;

Messaggio 208, livello 16, stato 0 Nome oggetto non valido '#Pivotato'. Questo perché #Pivoted è di proprietà della connessione Dynamic SQL. Quindi l'ultima istruzione

SELECT * FROM #Pivoted

non riesce.

Un modo per non affrontare questo problema è assicurarsi che tutti i riferimenti a #Pivoted siano fatti dall'interno della query dinamica stessa:

DECLARE @COMMA_SEPARATED_KEYS varchar(MAX);
DROP TABLE IF EXISTS KV;
CREATE TABLE KV (id_person int, mykey varchar(30), myvalue int);
INSERT INTO KV VALUES
(1, 'age', 16),
(1, 'weight', 63),
(1, 'height', 175),
(2, 'age', 26),
(2, 'weight', 83),
(2, 'height', 185);
WITH cte(mykey) AS (
    SELECT DISTINCT mykey FROM KV
) 
SELECT @COMMA_SEPARATED_KEYS=STRING_AGG(mykey,',') FROM cte;
SELECT @COMMA_SEPARATED_KEYS AS keys;


DECLARE @ExecuteExpression varchar(MAX);

DROP TABLE IF EXISTS #Pivoted;

SET @ExecuteExpression = N'
SELECT * 
INTO #Pivoted
FROM
(
    SELECT
        mykey,
        myvalue,
        id_person
    FROM KV
) AS t
PIVOT(
    MAX(t.myvalue) 
    FOR mykey IN (COMMA_SEPARATED_KEYS)
) AS pivot_table;
SELECT * FROM #Pivoted;
';

SET @ExecuteExpression = REPLACE(@ExecuteExpression, 'COMMA_SEPARATED_KEYS', @COMMA_SEPARATED_KEYS);

EXEC(@ExecuteExpression);

inserisci qui la descrizione dell'immagine


-5

Vorrei fare quanto segue

  1. Creare (convertire SP in) un UDF (valore tabella UDF).

  2. select * into #tmpBusLine from dbo.UDF_getBusinessLineHistory '16 Mar 2009'


2
Potrebbero esserci degli ostacoli per fare il tuo primo passo. Ad esempio, se l'SP originale utilizza tabelle temporanee. Gli UDF non possono utilizzare le tabelle temporanee.
yucer
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.