2009-10-19 15 views
17

Mi procedimiento almacenado se parece a:¿por qué no puedo acceder a mi CTE después de usarlo una vez?

WITH MYCTE(....) 
AS 
(
... 
) 

UPDATE ... (using my CTE) 



DELETE (using my CTE) <--- says the object, my CTE, doesn't exist 

se puede usar sólo una vez?

+0

Este es un buen ejemplo de por qué todos deberíamos usar punto y coma en nuestro T-SQL. Tener ';' colocado correctamente después de las instrucciones UPDATE y DELETE deja en claro que el CTE es _parte de_ la instrucción UPDATE. – NReilingh

Respuesta

19

En su código de ejemplo, el CTE solo persiste para la ACTUALIZACIÓN. Si necesita que dure más tiempo, considere llenar un #tempTable o @tableVariable con él, y luego ACTUALIZAR y ELIMINAR de ellos.

También puede aumentar su ACTUALIZACIÓN para utilizar una cláusula OUTPUT, como la siguiente, para que pueda capturar las filas afectadas. Y utilizarlos en el DELETE, como aquí:

set nocount on 
DECLARE @Table  table (PK int, col1 varchar(5)) 
DECLARE @SavedPks table (PK int) 

INSERT INTO @Table VALUES (1,'g') 
INSERT INTO @Table VALUES (2,'g') 
INSERT INTO @Table VALUES (3,'g') 
INSERT INTO @Table VALUES (4,'g') 
INSERT INTO @Table VALUES (5,'x') 
INSERT INTO @Table VALUES (6,'x') 
set nocount off 

;WITH MYCTE 
AS 
(
    SELECT PK, col1 FROM @Table 
) 
UPDATE MYCTE 
    SET col1='xyz' 
    OUTPUT INSERTED.PK 
     INTO @SavedPks 
    WHERE col1='g' 

SELECT 'A',* FROM @Table 

DELETE @Table 
    WHERE PK IN (SELECT PK from @SavedPks) 

SELECT 'B',* FROM @Table 

SALIDA:

(4 row(s) affected) 
    PK   col1 
---- ----------- ----- 
A 1   xyz 
A 2   xyz 
A 3   xyz 
A 4   xyz 
A 5   x 
A 6   x 

(6 row(s) affected) 

(4 row(s) affected) 

    PK   col1 
---- ----------- ----- 
B 5   x 
B 6   x 

(2 row(s) affected) 
+1

Gran respuesta. He estado usando SQL Server por años y no sabía que podrías hacer SALIDA. Eso definitivamente será útil en el futuro. – WesleyJohnson

3

Una expresión CTE solo es válida en su cuerpo. Si desea usarlo en otros lugares, también debe repetir la cláusula WITH.

WITH MYCTE(....) AS (...) 
UPDATE ... (using my CTE); 
-- a semicolon is necessary for statements followed by a CTE declaration 

WITH MYCTE(....) AS (...) 
DELETE (using my CTE); 
+0

pero está funcionando en la ACTUALIZACIÓN, pero no en el BORRAR, ¿tiene sentido? – mrblah

+0

Por supuesto. 'UPDATE' es el cuerpo de tu CTE. –

+0

No es el cuerpo dentro del() después de la palabra clave AS. Update y DELETE están fuera de(). – mrblah

3

Sí, la cláusula WITH MYCTE no está creando un objeto permanente para su uso en varias consultas después: es sólo la modificación de la consulta que se va a añadir a esa cláusula! Si necesita una funcionalidad muy diferente, considere, en cambio, usar vistas ...

+1

... o tablas temporales (# o @). –

4

CTE no crean nada 'real'. Son simplemente un elemento de lenguaje, una forma de expresar una expresión de tabla que se utilizará, posiblemente repetidamente, en una declaración. Cuando usted dice

WITH cteFoo AS (select ... from table where ...) 
select ... from cteFoo where ... 

es sólo otra forma de decir

select ... from (select ... from table where ....) as cteFoo where ... 

CTE y tablas derivadas son muy similares, cualquier consulta utilizando tablas derivadas puede ser regrabadas como CTE, y cualquier CTE no recursivo CAN ser reescrito como una consulta usando tablas derivadas. Personalmente, prefiero mucho más el formulario CTE porque es más conciso y fácil de leer.

CTEs permiten una expresión de tabla utilizar varias veces para ser declarar sólo una vez:

WITH cte AS (select ... from table where ...) 
    select ... 
    from cte a join cte b on ... 
    where ... 

comparar esto con la forma tabla derivada semánticamente similar:

select ... 
from (
    select ... from table where ...) as a 
join (
    select ... from table where ...) as b 
    on ... 
where ... 

El CTE es claramente más legible. Pero debe comprender que las dos formas están produciendo la misma consulta. El formulario CTE podría sugerir que se crea un resultado intermedio, luego la unión se ejecuta en el resultado intermedio, pero esto no es cierto. El formulario CTE se compila en exactamente la misma forma que la tabla derivada uno, lo que deja en claro el hecho de que la expresión de tabla del CTE se ejecuta dos veces.

Cuestiones relacionadas