在CTE中使用GROUP BY进行聚合

时间:2018-11-21 07:42:40

标签: sql sql-server tsql

我正在使用TSQL和AdventureWorks 2014尝试为由SalesOrderID指定的每个唯一订单计算所有LineTotal的总和。我要加入SalesOrderHead.SalesOrderID,因为在SalesOrderHeader中,SalesOrderID是主键。当每个SalesOrderID仅返回一条记录时,此查询将永久运行,并返回SalesOrderID的重复项。希望有道理...

我想做的是计算SumPerOrderCTE中按SalesOrderID分组的SUM(LineTotal),然后将其加入SalesOrderHeader以选择一些其他表,并且仅从SumPerOrder中选择具有与SalesOrderHeader匹配的SalesOrderID的记录。

有什么建议吗?我似乎无法弄清楚为什么它没有按期做。.

以下是输出(请注意,SalesOrderID都相同,并且的差异大部分应为0,但不同): buggy_output

关于输出外观的小样本: desired_output

CREATE OR ALTER PROC [dbo].[SalesOrderDataReviewCTE]
AS
WITH SumPerOrder (SalesOrderID, CalculatedSubTotalFromDetail)
AS
(
SELECT
    SalesOrderID
    ,SUM(LineTotal)
FROM AdventureWorks2014.Sales.SalesOrderDetail
GROUP BY SalesOrderID
)
SELECT
    soh.SalesOrderID
    ,soh.SalesOrderNumber
    ,soh.SubTotal AS OriginalSubTotal
    ,spo.CalculatedSubTotalFromDetail
    ,(soh.SubTotal - spo.CalculatedSubTotalFromDetail) AS Difference
FROM AdventureWorks2014.Sales.SalesOrderHeader soh
    INNER JOIN SumPerOrder spo
        ON soh.SalesOrderID = spo.SalesOrderID

2 个答案:

答案 0 :(得分:1)

为什么要使用CTE?

CTE只是使用可重复代码创建临时表的一种便捷且一次查询的方式。执行此操作时,SumPerOrder表将丢失SalesOrderDetail的所有索引。因此,与SalesOrderHeader的联接比与SalesOrderHeaderSalesOrderDetail的直接联接所花费的时间要长得多。

更简单的方法是:

SELECT
    soh.SalesOrderID
    ,soh.SalesOrderNumber
    ,soh.SubTotal AS OriginalSubTotal
    ,spo.SUM(LineTotal) as CalculatedSubTotalFromDetail
    ,(soh.SubTotal - spo.SUM(LineTotal)) AS Difference
FROM AdventureWorks2014.Sales.SalesOrderHeader soh
    INNER JOIN AdventureWorks2014.Sales.SalesOrderDetail spo
        ON soh.SalesOrderID = spo.SalesOrderID
GROUP BY spo.SalesOrderID,soh.SalesOrderNumber,soh.SubTotal

答案 1 :(得分:0)

您的查询似乎运行正常:

enter image description here

请检查其他问题。