2009-10-19 104 views
17

我的存储过程是这样的:为什么我使用一次后无法访问我的CTE?

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

UPDATE ... (using my CTE) 



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

我只能用一次?

+0

这是我们为什么应该在我们的T-SQL中使用分号的一个很好的例子。在UPDATE和DELETE语句之后正确放置';'表明CTE是UPDATE语句的_part。 – NReilingh 2017-01-08 20:40:52

回答

19

在您的示例代码中,CTE仅保留UPDATE。如果您需要更长的时间,请考虑使用它填充#tempTable或@tableVariable,然后从中更新和删除。

您也可以增加您的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 

OUTPUT:

(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

很棒的回答。我一直在使用SQL Server多年,并不知道你可以做OUTPUT。这在将来肯定会派上用场。 – WesleyJohnson 2009-10-20 01:04:34

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); 
+0

但它在UPDATE中工作,只是不在DELETE中,这是否有意义? – mrblah 2009-10-19 20:43:15

+0

当然。 'UPDATE'是你CTE的主体。 – 2009-10-19 20:46:39

+0

不是AS关键字后面的()中的body。更新和DELETE在()之外。 – mrblah 2009-10-19 20:49:44

3

是的,在WITH MYCTE条款不产生永久的对象之后多个查询使用方法:它只是修改要添加该条款的一个查询!如果您需要非常不同的功能,请考虑使用视图...

+1

...或临时表(#或@)。 – 2009-10-19 20:52:35

4

CTE不创造任何 '真正的'。它们仅仅是一个语言元素,这是一种表达式,可以在语句中重复使用这种表格。当你说

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

是说

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

CTE的只是另一种方式和派生表非常相似,使用派生表的任何查询可以rewriten的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表格被编译成与派生表格完全相同的形式,这明确了CTE的表格表达式运行两次

相关问题