Kombinieren von INSERT INTO und WITH / CTE

157

Ich habe einen sehr komplexen CTE und möchte das Ergebnis in eine physische Tabelle einfügen.

Ist folgendes gültig?

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

Ich denke darüber nach, eine Funktion zum Erstellen dieses CTE zu verwenden, mit der ich sie wiederverwenden kann. Irgendwelche Gedanken?

dcpartners
quelle

Antworten:

270

Sie müssen zuerst den CTE setzen und dann INSERT INTO mit Ihrer select-Anweisung kombinieren. Das Schlüsselwort "AS" nach dem Namen des CTE ist ebenfalls nicht optional:

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

Bitte beachten Sie, dass der Code davon ausgeht, dass der CTE genau vier Felder zurückgibt und dass diese Felder in Reihenfolge und Typ mit den in der INSERT-Anweisung angegebenen übereinstimmen. Ist dies nicht der Fall, ersetzen Sie einfach "SELECT *" durch eine bestimmte Auswahl der gewünschten Felder.

Was Ihre Frage zur Verwendung einer Funktion betrifft, würde ich sagen "es kommt darauf an". Wenn Sie die Daten nur aus Leistungsgründen in eine Tabelle einfügen und die Geschwindigkeit bei Verwendung über eine Funktion akzeptabel ist, würde ich die Funktion als Option betrachten. Wenn Sie andererseits das Ergebnis des CTE in mehreren verschiedenen Abfragen verwenden müssen und die Geschwindigkeit bereits ein Problem darstellt, würde ich mich für eine Tabelle entscheiden (entweder regulär oder temporär).

WITH common_table_expression (Transact-SQL)

Valentino Vranken
quelle
19

Die WITHKlausel für allgemeine Tabellenausdrücke steht oben.

Das Umschließen jeder Einfügung in einen CTE hat den Vorteil, dass die Abfragelogik visuell von der Spaltenzuordnung getrennt wird.

Finde den Fehler:

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_

Gleicher Fehler:

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

Ein paar Zeilen Boilerplate machen es extrem einfach zu überprüfen, ob der Code die richtige Anzahl von Spalten in der richtigen Reihenfolge einfügt, selbst bei einer sehr großen Anzahl von Spalten. Dein zukünftiges Selbst wird es dir später danken.

Anon
quelle
3
Das ist toll! Plötzlich hasse ich INSERT-Aussagen nicht mehr so ​​sehr ...
NReilingh
1
Dies ist äußerst nützlich. Für alle anderen, die es bei der ersten Lesung verpasst haben, besteht das Problem darin, dass in einer insert-Anweisung die Zuordnung durch die relative Reihenfolge der einzufügenden Felder und der darin einzufügenden Werte definiert wird, die separat aufgeführt sind. Wenn Sie diese normalerweise schreiben, ist es unglaublich schwierig, durch visuelle Inspektion zu überprüfen, ob die beiden Bestellungen gleich sind. Mit dem CTE können Sie die Werte mit den Spaltennamen benennen, in die sie eingefügt werden sollen, was bedeutet, dass Sie diese wirklich gut auf zwei Zeilen ausrichten können.
Tidorith
16

Ja:

WITH tab (
  bla bla
)

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

SELECT * FROM tab

Beachten Sie, dass dies für SQL Server gilt, der mehrere CTEs unterstützt:

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

Teradata erlaubt nur einen CTE und die Syntax ist als Beispiel.

Cade Roux
quelle