使用 CASE 表达式作为列别名、SUM、GROUP BY 和子查询时出错
Error using CASE expression as column alias, SUM, GROUP BY, and subquery
我有两个 table:Orders 和 ODetail。我想创建一个 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 BY
列 Year, 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) 可能会抱怨没有名为 Year
或 ProductLine
的列。这可能就是您使用内部查询的原因。您将不得不重复内联字段定义:
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
请注意,您必须避免选择 *
,这样您就可以将分组列与聚合列分开,并确保在内部查询中包含要聚合的列。
我有两个 table:Orders 和 ODetail。我想创建一个 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 BY
列 Year, 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) 可能会抱怨没有名为 Year
或 ProductLine
的列。这可能就是您使用内部查询的原因。您将不得不重复内联字段定义:
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
请注意,您必须避免选择 *
,这样您就可以将分组列与聚合列分开,并确保在内部查询中包含要聚合的列。