Combinando INSERT INTO e WITH / CTE


157

Ho un CTE molto complesso e vorrei inserire il risultato in una tabella fisica.

È valido quanto segue?

INSERT INTO dbo.prf_BatchItemAdditionalAPartyNos 
(
    BatchID,
    AccountNo,
    APartyNo,
    SourceRowID
)       
WITH tab (
  -- some query
)    
SELECT * FROM tab

Sto pensando di utilizzare una funzione per creare questo CTE che mi permetterà di riutilizzare. qualche idea?

Risposte:


271

È necessario inserire prima CTE e quindi combinare INSERT INTO con l'istruzione select. Inoltre, la parola chiave "AS" che segue il nome del CTE non è facoltativa:

WITH tab AS (
    bla bla
)
INSERT INTO dbo.prf_BatchItemAdditionalAPartyNos (
BatchID,
AccountNo,
APartyNo,
SourceRowID
)  
SELECT * FROM tab

Si noti che il codice presuppone che il CTE restituirà esattamente quattro campi e che tali campi corrispondano nell'ordine e nel tipo con quelli specificati nell'istruzione INSERT. In caso contrario, basta sostituire "SELEZIONA *" con una selezione specifica dei campi richiesti.

Per quanto riguarda la tua domanda sull'uso di una funzione, direi "dipende". Se stai inserendo i dati in una tabella solo per motivi di prestazioni e la velocità è accettabile quando li usi attraverso una funzione, considererei la funzione come un'opzione. D'altra parte, se è necessario utilizzare il risultato del CTE in diverse query e la velocità è già un problema, sceglierei un tavolo (normale o temporaneo).

WITH common_table_expression (Transact-SQL)


19

La WITHclausola per Common Table Expressions va in alto.

Il wrapping di ogni inserto in un CTE ha il vantaggio di separare visivamente la logica della query dalla mappatura delle colonne.

Trova l'errore:

WITH _INSERT_ AS (
  SELECT
    [BatchID]      = blah
   ,[APartyNo]     = blahblah
   ,[SourceRowID]  = blahblahblah
  FROM Table1 AS t1
)
INSERT Table2
      ([BatchID], [SourceRowID], [APartyNo])
SELECT [BatchID], [APartyNo], [SourceRowID]   
FROM _INSERT_

Stesso errore:

INSERT Table2 (
  [BatchID]
 ,[SourceRowID]
 ,[APartyNo]
)
SELECT
  [BatchID]      = blah
 ,[APartyNo]     = blahblah
 ,[SourceRowID]  = blahblahblah
FROM Table1 AS t1

Alcune righe di plateplate rendono estremamente facile verificare che il codice inserisca il giusto numero di colonne nel giusto ordine, anche con un numero molto elevato di colonne. Il tuo sé futuro ti ringrazierà più tardi.


3
Questo è fantastico! Improvvisamente, non odio le dichiarazioni INSERT ...
NReilingh,

1
Questo è estremamente utile. Per chiunque lo abbia perso in prima lettura, il problema che questo risolve è che in un'istruzione insert la mappatura è definita dall'ordinamento relativo dei campi da inserire e dai valori da inserire in essi, che sono elencati separatamente. Se li scrivi normalmente è incredibilmente difficile verificare con un'ispezione visiva che i due ordini siano gli stessi. Il CTE ti consente di nominare i valori con i nomi delle colonne in cui verranno inseriti, il che significa che puoi allinearli davvero bene su due righe.
Tidorith,

16

Sì:

WITH tab (
  bla bla
)

INSERT INTO dbo.prf_BatchItemAdditionalAPartyNos (  BatchID,                                                        AccountNo,
APartyNo,
SourceRowID)    

SELECT * FROM tab

Si noti che questo è per SQL Server, che supporta più CTE:

WITH x AS (), y AS () INSERT INTO z (a, b, c) SELECT a, b, c FROM y

Teradata consente solo un CTE e la sintassi è come il tuo esempio.

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.