Combinando INSERT INTO y WITH / CTE

157

Tengo un CTE muy complejo y me gustaría insertar el resultado en una tabla física.

¿Es válido lo siguiente?

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

Estoy pensando en usar una función para crear este CTE que me permita reutilizar. ¿Alguna idea?

dcpartners
fuente

Respuestas:

271

Primero debe poner el CTE y luego combinar INSERT INTO con su instrucción select. Además, la palabra clave "AS" que sigue al nombre del CTE no es opcional:

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

Tenga en cuenta que el código supone que el CTE devolverá exactamente cuatro campos y que esos campos coinciden en orden y tipo con los especificados en la instrucción INSERT. Si ese no es el caso, simplemente reemplace el "SELECCIONAR *" con una selección específica de los campos que necesita.

En cuanto a su pregunta sobre el uso de una función, diría "depende". Si coloca los datos en una tabla solo por razones de rendimiento, y la velocidad es aceptable cuando se usa a través de una función, entonces consideraría que la función es una opción. Por otro lado, si necesita usar el resultado del CTE en varias consultas diferentes, y la velocidad ya es un problema, elegiría una tabla (ya sea regular o temporal).

WITH common_table_expression (Transact-SQL)

Valentino Vranken
fuente
19

La WITHcláusula para las expresiones de tabla comunes va en la parte superior.

Ajustar cada inserto en un CTE tiene la ventaja de segregar visualmente la lógica de consulta de la asignación de columnas.

Encuentra el fallo:

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_

Mismo error:

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

Algunas líneas de repeticiones hacen que sea extremadamente fácil verificar que el código inserte la cantidad correcta de columnas en el orden correcto, incluso con una gran cantidad de columnas. Tu futuro yo te lo agradecerá más tarde.

Luego
fuente
3
¡Esto es genial! De repente, no odio las declaraciones INSERT tanto ...
NReilingh
1
Esto es extremadamente útil. Para cualquier otra persona que se lo haya perdido en la primera lectura, el problema que esto resuelve es que en una declaración de inserción, la asignación se define por el orden relativo de los campos que se insertarán y los valores que se insertarán en ellos, que se enumeran por separado. Si escribe esto normalmente, es increíblemente difícil verificar mediante inspección visual que los dos ordenamientos sean iguales. El CTE le permite nombrar los valores con los nombres de columna en los que se van a insertar, lo que significa que puede alinearlos muy bien en dos líneas.
Tidorith
16

Sí:

WITH tab (
  bla bla
)

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

SELECT * FROM tab

Tenga en cuenta que esto es para SQL Server, que admite varios CTE:

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

Teradata solo permite un CTE y la sintaxis es su ejemplo.

Cade Roux
fuente