Combinando INSERT INTO e WITH / CTE

157

Eu tenho uma CTE muito complexa e gostaria de inserir o resultado em uma tabela física.

O seguinte é válido?

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

Estou pensando em usar uma função para criar este CTE que me permitirá reutilizar. Alguma ideia?

dcpartners
fonte

Respostas:

271

Você precisa colocar o CTE primeiro e depois combinar o INSERT INTO com sua instrução select. Além disso, a palavra-chave "AS" após o nome do CTE não é opcional:

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

Observe que o código pressupõe que o CTE retornará exatamente quatro campos e que esses campos estejam em ordem e digite com os especificados na instrução INSERT. Se não for esse o caso, substitua "SELECT *" por uma seleção específica dos campos necessários.

Quanto à sua pergunta sobre o uso de uma função, eu diria "depende". Se você estiver colocando os dados em uma tabela apenas por razões de desempenho e a velocidade for aceitável ao usá-los por meio de uma função, consideraria a função uma opção. Por outro lado, se você precisar usar o resultado do CTE em várias consultas diferentes e a velocidade já for um problema, eu usaria uma tabela (regular ou temporária).

COM expressão_tabela_ comum (Transact-SQL)

Valentino Vranken
fonte
19

A WITHcláusula para expressões comuns de tabela fica no topo.

O agrupamento de todas as inserções em um CTE tem o benefício de segregar visualmente a lógica da consulta do mapeamento da coluna.

Descubra o erro:

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_

Mesmo erro:

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

Algumas linhas de clichê facilitam extremamente a verificação de que o código insere o número certo de colunas na ordem certa, mesmo com um número muito grande de colunas. Seu futuro eu agradecerá mais tarde.

Anon
fonte
3
Isso é ótimo! De repente, eu não odeio instruções INSERT tanto ...
NReilingh
1
Isso é extremamente útil. Para quem perdeu na primeira leitura, o problema que isso resolve é que, em uma instrução de inserção, o mapeamento é definido pela ordem relativa dos campos a serem inseridos e pelos valores a serem inseridos neles, listados separadamente. Se você as escrever normalmente, é incrivelmente difícil verificar por inspeção visual se as duas ordens são iguais. O CTE permite que você nomeie os valores com os nomes das colunas nas quais eles serão inseridos, o que significa que você pode alinhar esses valores muito bem em duas linhas.
Tidorith
16

Sim:

WITH tab (
  bla bla
)

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

SELECT * FROM tab

Observe que isso é para o SQL Server, que suporta vários CTEs:

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

O Teradata permite apenas um CTE e a sintaxe é o seu exemplo.

Cade Roux
fonte