我用过一次后为什么不能访问我的CTE?

时间:2009-10-19 20:37:40

标签: sql sql-server common-table-expression

我的存储过程如下:

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

UPDATE ... (using my CTE)



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

我可以只使用一次吗?

4 个答案:

答案 0 :(得分:21)

在您的示例代码中,CTE仅保留UPDATE。如果你需要它持续更长时间,可以考虑用它填充#tempTable或@tableVariable,然后再从那些中填充UPDATE和DELETE。

您还可以扩充UPDATE以使用OUTPUT子句,如下所示,以便捕获受影响的行。并在DELETE中使用它们,如下所示:

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

输出:

(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 :(得分:3)

CTE表达式仅在其正文中有效。如果你想在其他地方使用它,你也应该重复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); 

答案 2 :(得分:3)

是的,WITH MYCTE子句后面没有创建一个永久对象用于多个查询:它只修改你要添加该子句的一个查询!如果您需要非常不同的功能,请考虑使用视图......

答案 3 :(得分:3)

CTE不会创造任何“真实”的东西。它们只是一个语言元素,是一种表达将在语句中重复使用的表表达式的方法。当你说

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

只是另一种说法

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

CTE和派生表非常相似,任何使用派生表的查询都可以重写为CTE,任何非递归CTE都可以使用派生表重写为查询。就个人而言,我更倾向于使用CTE表格,因为它更简洁易读。

CTE允许多次使用的表表达式只能声明一次:

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

将其与语义相似的派生表格形式进行比较:

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

CTE显然更具可读性。但是你必须明白这两种形式正在产生相同的查询。 CTE表单可能表明创建了一个中间结果,然后在中间结果上运行连接,但事实并非如此。 CTE表单被编译成与派生表格1完全相同的形式,这清楚地表明了CTE的表格表达式运行两次