7

当我在我的一个脚本中使用 WITH 子句时,我遇到了一个问题。这个问题很容易指出我想多次使用 CTE 别名,而不是只在外部查询中使用,并且有症结所在。

例如:

-- Define the CTE expression
WITH cte_test (domain1, domain2, [...])
AS
-- CTE query
(
    SELECT domain1, domain2, [...]
    FROM table
)
-- Outer query
SELECT * FROM cte_test
-- Now I wanna use the CTE expression another time
INSERT INTO sometable ([...]) SELECT [...] FROM cte_test

最后一行将导致以下错误,因为它在外部查询之外:

消息 208,级别 16,状态 1,第 12 行无效的对象名称“cte_test”。

有没有办法多次使用 CTE。让它持久化?我当前的解决方案是创建一个临时表,在其中存储 CTE 的结果,并将此临时表用于任何进一步的语句。

-- CTE
[...]
-- Create a temp table after the CTE block
DECLARE  @tmp TABLE (domain1 DATATYPE, domain2 DATATYPE, [...])
INSERT INTO @tmp (domain1, domain2, [...]) SELECT domain1, domain2, [...] FROM cte_test
-- Any further DML statements
SELECT * FROM @tmp
INSERT INTO sometable ([...]) SELECT [...] FROM @tmp
[...]

坦率地说,我不喜欢这种解决方案。有没有其他人有这个问题的最佳实践?

提前致谢!

4

2 回答 2

18

CommonTableExpression 不会以任何方式持久化数据。它基本上只是在主查询本身之前创建子查询的一种方式。

这使它更像是一个内联视图,而不是一个普通的子查询。因为您可以在一个查询中重复引用它,而不必一次又一次地键入它。

但它仍然只是被视为一个视图,扩展为引用它的查询,类似于宏。根本没有数据的持久化。


不幸的是,这对您来说意味着您必须自己坚持。

  • 如果您希望 CTE 的逻辑被持久化,您不需要内联视图,您只需要一个视图。

  • 如果您希望 CTE 的结果集被持久化,您需要一种临时表类型的解决方案,例如您不喜欢的解决方案。

于 2012-06-01T12:07:50.497 回答
9

CTE 仅在它所属的 SQL 语句的范围内。如果您需要在后续语句中重用其数据,则需要一个临时表或表变量来存储数据。在您的示例中,除非您正在实现递归 CTE,否则我根本不需要 CTE - 您可以将其内容直接存储在临时表/表变量中,并尽可能多地重复使用它。

另请注意,您的 DELETE 语句将尝试从基础表中删除,这与您将结果放入临时表/表变量不同。

于 2012-06-01T12:02:34.453 回答