将CASE表达式用作列别名,SUM,GROUP BY和子查询时出错

时间:2015-03-24 00:57:24

标签: sql-server tsql group-by sum case

我有两个表: Orders ODetail 。我想创建一个表格,显示按年份,季度和产品线分组的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列之外的所有列进行分组时,查询工作正常。有任何想法吗?

2 个答案:

答案 0 :(得分:2)

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

当您GROUP BYYear, Quarter, ProductLine时,您要“选择与年份,季度和产品系列匹配的多个行,但随后将其汇总并汇总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

警告:如果您的查询发生更改,列别名将会更改,并且可能无法维护,但适用于即席查询。

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

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

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

答案 1 :(得分:1)

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

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