保持简单以及如何在查询中进行多个CTE


156

我有这个简单的T-SQL查询,它从一个表中发出一堆列,并且还连接其他相关表中的信息。

我的数据模型很简单。我有一个预定的活动,有参与者。我需要知道每个活动有多少参与者。

我对此的解决方案是添加一个CTE,该CTE对计划的事件进行分组并计算参与者的数量。

这将使我能够在每个计划的活动中加入该信息。使查询保持简单。

我希望使查询保持简单,但是,如果将来在简单查询期间需要访问附加的临时结果,该怎么办?

如果可以有多个CTE,但我不能,我真的很喜欢,对吗?我在这里有什么选择?

我已经排除了在应用程序数据层的视图和操作。我更喜欢隔离我的SQL查询。

Answers:


297

您可以CTE在一个查询中包含多个,并重用a CTE

WITH    cte1 AS
        (
        SELECT  1 AS id
        ),
        cte2 AS
        (
        SELECT  2 AS id
        )
SELECT  *
FROM    cte1
UNION ALL
SELECT  *
FROM    cte2
UNION ALL
SELECT  *
FROM    cte1

但是请注意,这SQL Server可能会重新评估CTE其访问的每个时间,因此,如果您使用的是类似的值RAND()NEWID()等等,它们可以在之间进行切换CTE通话。


3
就这么简单。MSDN文档对此问题有点模糊,我找不到结论性的东西。非常感谢你!
约翰·莱德格伦

1
它记录在WITH common_table_expression(Transact-SQL)中。您可以在语法部分中看到这一点(请特别注意[ ,...n ]in [ WITH <common_table_expression> [ ,...n ] ]。示例C,“在单个查询中使用多个CTE定义”,显式地指出了这一点。可悲的是,SQL 2008和2000的文档中未提供此示例。 (例如,OP在发布问题时未提供示例)
布莱恩(Brian

我得到的记录数量是这个记录的两倍:/
Tom Stickel

@TomStickel仅尝试使用查询的一半,而不是最后一个UNION ALL
Quassnoi

@Quassnoi是的。我写完评论后就这样做了。不知道为什么第二个工会甚至在那里...
汤姆·斯蒂克

89

您当然可以在单个查询表达式中具有多个CTE。您只需要用逗号分隔即可。这是一个例子。在下面的示例中,有两个CTE。一个被命名CategoryAndNumberOfProducts,第二个被命名ProductsOverTenDollars

WITH CategoryAndNumberOfProducts (CategoryID, CategoryName, NumberOfProducts) AS
(
   SELECT
      CategoryID,
      CategoryName,
      (SELECT COUNT(1) FROM Products p
       WHERE p.CategoryID = c.CategoryID) as NumberOfProducts
   FROM Categories c
),

ProductsOverTenDollars (ProductID, CategoryID, ProductName, UnitPrice) AS
(
   SELECT
      ProductID,
      CategoryID,
      ProductName,
      UnitPrice
   FROM Products p
   WHERE UnitPrice > 10.0
)

SELECT c.CategoryName, c.NumberOfProducts,
      p.ProductName, p.UnitPrice
FROM ProductsOverTenDollars p
   INNER JOIN CategoryAndNumberOfProducts c ON
      p.CategoryID = c.CategoryID
ORDER BY ProductName

5
@JohnLeidegren:至少在我给出第一个正确答案后的2分钟内发布正确答案是值得的。
Peter Majeed 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.