【问题标题】:Output to Table Variable, Not CTE输出到表变量,而不是 CTE
【发布时间】:2011-09-11 04:33:12
【问题描述】:

为什么这是合法的:

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

第二个块给我错误“在不是 INSERT 语句的直接行源的 SELECT 语句中不允许嵌套的 INSERT、UPDATE、DELETE 或 MERGE 语句。

似乎是说允许嵌套的 INSERT 语句,但在我的 CTE 案例中,我没有嵌套在另一个 INSERT 中。我对这个限制感到惊讶。我的 CTE 案例有什么变通办法吗?

【问题讨论】:

  • 错误信息对我来说似乎很清楚。不允许像这样将插入语句嵌套在SELECT 中。如果允许,那么如果您执行 SELECT TOP 10 * FROM Hey CROSS JOIN SomeOtherTable 会执行 10 次插入,您会发生什么?
  • 你有这样做的理由吗?还是只是实验?
  • 事实上,您的(无效)CTE 示例仅相当于 INSERT INTO SomeOtherTable OUTPUT inserted.Name VALUES ('Hello')

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


【解决方案1】:

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

CTE不会提前具体化到他们自己的临时表中,那么以下应该返回什么?

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

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

大概避免这种混乱是这种限制的动机(就像对函数副作用的限制一样)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-22
    • 2015-11-27
    • 2021-11-18
    • 2019-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多