输出到表变量,而不是CTE

时间:2011-09-11 04:33:12

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

为什么这是合法的:

DECLARE @Party TABLE 
(
  PartyID nvarchar(10)
)

INSERT INTO @Party
  SELECT Name FROM
  (INSERT INTO SomeOtherTable
     OUTPUT inserted.Name
          VALUES ('hello')) [H]

SELECT * FROM @Party

但是下一个块给了我一个错误:

WITH Hey (Name) 
AS (
  SELECT Name FROM
  (INSERT INTO SomeOtherTable
    OUTPUT inserted.Name
    VALUES ('hello')) [H]
        )

SELECT * FROM Hey

第二个块给出了错误“SELECT语句中不允许使用嵌套的INSERT,UPDATE,DELETE或MERGE语句,该语句不是INSERT语句的直接行源。

似乎是说允许使用嵌套的INSERT语句,但在我的CTE情况下,我没有嵌套在另一个INSERT中。我对这个限制感到惊讶。在我的CTE案例中有任何解决方法吗?

1 个答案:

答案 0 :(得分:1)

至于为什么这是非法的,允许这些带有副作用的SELECT操作会引起我想象的各种问题。

CTE 提前实现到他们自己的临时表中,那么下面的内容应该返回什么?

;WITH Hey (Name) 
AS 
(
...
)
SELECT name 
FROM Hey
JOIN some_other_table ON Name = name

如果查询优化器决定使用嵌套循环计划和Hey作为驱动表,那么可能会发生一次插入。但是,如果它使用some_other_table作为驱动表,则CTE将被评估为与其他表中的行一样多次,因此将发生多个插入。除非查询优化器决定在计划中添加一个假脱机,然后它才会被评估一次。

据推测,避免这种混乱是这种限制的动机(与功能中副作用的限制一样)