Combinaison INSERT INTO et WITH / CTE

157

J'ai un CTE très complexe et je voudrais insérer le résultat dans une table physique.

Est-ce que ce qui suit est valide?

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

Je pense utiliser une fonction pour créer ce CTE qui me permettra de le réutiliser. Des pensées?

dcpartners
la source

Réponses:

271

Vous devez d'abord mettre le CTE, puis combiner INSERT INTO avec votre instruction select. De plus, le mot-clé "AS" qui suit le nom du CTE n'est pas facultatif:

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

Veuillez noter que le code suppose que le CTE renverra exactement quatre champs et que ces champs correspondent dans l'ordre et le type avec ceux spécifiés dans l'instruction INSERT. Si ce n'est pas le cas, remplacez simplement "SELECT *" par une sélection spécifique des champs dont vous avez besoin.

Quant à votre question sur l'utilisation d'une fonction, je dirais "ça dépend". Si vous mettez les données dans un tableau uniquement pour des raisons de performances et que la vitesse est acceptable lors de son utilisation via une fonction, je considérerais la fonction comme une option. D'un autre côté, si vous avez besoin d'utiliser le résultat du CTE dans plusieurs requêtes différentes et que la vitesse est déjà un problème, j'opterais pour une table (régulière ou temporaire).

WITH common_table_expression (Transact-SQL)

Valentino Vranken
la source
19

La WITHclause pour les expressions de table communes va en haut.

L'emballage de chaque insert dans un CTE présente l'avantage de séparer visuellement la logique de requête du mappage de colonne.

Repérez l'erreur:

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_

Même erreur:

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

Quelques lignes de passe-partout rendent extrêmement facile la vérification que le code insère le bon nombre de colonnes dans le bon ordre, même avec un très grand nombre de colonnes. Votre futur moi vous remerciera plus tard.

Anon
la source
3
C'est bien! Tout à coup, je ne déteste pas autant les déclarations INSERT ...
NReilingh
1
Ceci est extrêmement utile. Pour quiconque l'a manqué lors de la première lecture, le problème que cela résout est que dans une instruction d'insertion, le mappage est défini par l'ordre relatif des champs à insérer et les valeurs à insérer dans ces derniers, qui sont répertoriés séparément. Si vous les écrivez normalement, il est extrêmement difficile de vérifier par inspection visuelle que les deux ordres sont identiques. Le CTE vous permet de nommer les valeurs avec les noms de colonnes dans lesquelles elles vont être insérées, ce qui signifie que vous pouvez les aligner très bien sur deux lignes.
Tidorith le
16

Oui:

WITH tab (
  bla bla
)

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

SELECT * FROM tab

Notez qu'il s'agit de SQL Server, qui prend en charge plusieurs CTE:

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

Teradata n'autorise qu'un seul CTE et la syntaxe est à titre d'exemple.

Cade Roux
la source