使用 CASE 表达式作为列别名、SUM、GROUP BY 和子查询时出错

Error using CASE expression as column alias, SUM, GROUP BY, and subquery

我有两个 table:OrdersODetail。我想创建一个 table 来显示 2012 年按年、季度和产品线分组的销售额总和(这是一个案例)。这是我的 SQL 代码:

SELECT * FROM 

(SELECT 
YEAR(o.OrderDate) 'Year', DATEPART(Quarter, o.OrderDate) 'Quarter',
                    CASE 
                    WHEN SUBSTRING (od.PNum, 4, 1)= 'M' THEN 'Motors'
                    WHEN SUBSTRING(od.PNUM, 4, 1)= 'T' THEN 'Trolling Motors'
                    WHEN SUBSTRING(od.PNum, 4, 1)= 'P' THEN 'Pumps'
                END  ProductLine,
                SUM(od.QPrice*od.Quantity)




FROM Orders o, ODetail od
WHERE o.OrderNum=od.OrderNum
AND YEAR(o.OrderDate)=2012

)a

GROUP BY a.Year, a.Quarter, a.ProductLine

出于某种原因,我仍然收到与 GROUP BY 相关的错误。当我尝试对除 SUM 列以外的所有列进行分组时,查询工作得很好。有任何想法吗?

您可以在没有子查询的情况下执行此操作:

SELECT
    YEAR(o.OrderDate) AS [Year],
    DATEPART(QUARTER, o.OrderDate) AS [Quarter],
    CASE
        WHEN SUBSTRING(od.PNum, 4, 1)= 'M' THEN 'Motors'
        WHEN SUBSTRING(od.PNUM, 4, 1)= 'T' THEN 'Trolling Motors'
        WHEN SUBSTRING(od.PNum, 4, 1)= 'P' THEN 'Pumps' 
    END AS ProductLine,
    SUM(od.QPrice * od.Quantity)
FROM Orders o
INNER JOIN Odetail od
    ON o.OrderNum = od.OrderNum
WHERE
    o.OrderDate >= CAST('20120101' AS DATE)
    AND o.OrderDate < CAST('20130101' AS DATE)
GROUP BY 
    YEAR(o.OrderDate), 
    DATEPART(QUARTER, o.OrderDate),
    CASE
        WHEN SUBSTRING(od.PNum, 4, 1)= 'M' THEN 'Motors'
        WHEN SUBSTRING(od.PNUM, 4, 1)= 'T' THEN 'Trolling Motors'
        WHEN SUBSTRING(od.PNum, 4, 1)= 'P' THEN 'Pumps' 
    END

注意:避免使用旧式 JOIN 语法。阅读 Aaron Bertrand 的 article

GROUP BY 将告知哪些列被分组并应用于聚合函数,在本例中为 SUM。如果您将内部查询(您的别名 a)视为一个单独的查询,将更容易看到错误。然后,你会看到你有 SUM 但没有 GROUP BY.

当您 GROUP BYYear, Quarter, ProductLine 时,您说的是 "select multiple rows that match a year, quarter, and product line, but then roll them up and sum the value of Price*Quantity".

因此,您可以将 GROUP BY 与内部查询放在一起:

SELECT * FROM 

(SELECT 
YEAR(o.OrderDate) 'Year', DATEPART(Quarter, o.OrderDate) 'Quarter',
                    CASE 
                    WHEN SUBSTRING (od.PNum, 4, 1)= 'M' THEN 'Motors'
                    WHEN SUBSTRING(od.PNUM, 4, 1)= 'T' THEN 'Trolling Motors'
                    WHEN SUBSTRING(od.PNum, 4, 1)= 'P' THEN 'Pumps'
                END  ProductLine,
                SUM(od.QPrice*od.Quantity)




FROM Orders o, ODetail od
WHERE o.OrderNum=od.OrderNum
AND YEAR(o.OrderDate)=2012
GROUP BY Year, Quarter, ProductLine

)a

哪个 A) 使内部查询变得多余,B) 可能会抱怨没有名为 YearProductLine 的列。这可能就是您使用内部查询的原因。您将不得不重复内联字段定义:

GROUP BY YEAR(o.OrderDate), DATEPART(Quarter, o.OrderDate), CASE 
                    WHEN SUBSTRING (od.PNum, 4, 1)= 'M' THEN 'Motors'
                    WHEN SUBSTRING(od.PNUM, 4, 1)= 'T' THEN 'Trolling Motors'
                    WHEN SUBSTRING(od.PNum, 4, 1)= 'P' THEN 'Pumps'
                END

或者您可以(不寒而栗)按列位置别名分组:

GROUP BY 1, 2, 3

注意:如果您的查询发生变化,列别名也会发生变化,并且可能不太易于维护,但对于即席查询来说效果很好。

最后,您可以将 SUM 移到外面,而不是将 GROUP BY 移到里面:

SELECT a.Year, a.Quarter, a.ProductLine, SUM(a.QPrice*a.Quantity) FROM 

(SELECT 
YEAR(o.OrderDate) 'Year', DATEPART(Quarter, o.OrderDate) 'Quarter',
                    CASE 
                    WHEN SUBSTRING (od.PNum, 4, 1)= 'M' THEN 'Motors'
                    WHEN SUBSTRING(od.PNUM, 4, 1)= 'T' THEN 'Trolling Motors'
                    WHEN SUBSTRING(od.PNum, 4, 1)= 'P' THEN 'Pumps'
                END  ProductLine,
                od.QPrice,
                od.Quantity




FROM Orders o, ODetail od
WHERE o.OrderNum=od.OrderNum
AND YEAR(o.OrderDate)=2012

) a

GROUP BY a.Year, a.Quarter, a.ProductLine

请注意,您必须避免选择 *,这样您就可以将分组列与聚合列分开,并确保在内部查询中包含要聚合的列。