SQL - 聚合函数中的子查询

时间:2013-05-01 12:07:34

标签: sql subquery sql-server-2012 aggregate-functions northwind

我正在使用northwind数据库通过创建一些或多或少复杂的查询来刷新我的SQL技能。不幸的是我无法找到我最后一个用例的解决方案: “获取1997年每个类别的五个最大订单的总和。”

所涉及的表格是:

Orders(OrderId, OrderDate)
Order Details(OrderId, ProductId, Quantity, UnitPrice)
Products(ProductId, CategoryId)
Categories(CategoryId, CategoryName)

我尝试了以下查询

SELECT c.CategoryName, SUM(
  (SELECT TOP 5 od2.UnitPrice*od2.Quantity 
   FROM [Order Details] od2, Products p2
   WHERE od2.ProductID = p2.ProductID
   AND c.CategoryID = p2.CategoryID
   ORDER BY 1 DESC))
FROM [Order Details] od, Products p, Categories c, Orders o 
WHERE od.ProductID = p. ProductID
AND p.CategoryID = c.CategoryID
AND od.OrderID = o.OrderID
AND YEAR(o.OrderDate) = 1997
GROUP BY c.CategoryName

嗯......事实证明,聚合函数中不允许使用子查询。我已经阅读了有关此问题的其他帖子,但无法找到针对我的特定用例的解决方案。希望你能帮助我...

4 个答案:

答案 0 :(得分:24)

聚合函数通常不允许使用子查询。相反,将聚合移动到子查询中。在这种情况下,由于top 5

,您需要额外级别的子查询
SELECT c.CategoryName,
  (select sum(val)
   from (SELECT TOP 5 od2.UnitPrice*od2.Quantity as val
         FROM [Order Details] od2, Products p2
         WHERE od2.ProductID = p2.ProductID
         AND c.CategoryID = p2.CategoryID
         ORDER BY 1 DESC
        ) t
  )
FROM [Order Details] od, Products p, Categories c, Orders o 
WHERE od.ProductID = p. ProductID
AND p.CategoryID = c.CategoryID
AND od.OrderID = o.OrderID
AND YEAR(o.OrderDate) = 1997
GROUP BY c.CategoryName, c.CategoryId

答案 1 :(得分:4)

CTEROW_NUMBER排名函数一起使用,而不是使用过多的子查询。

 ;WITH cte AS
 (
  SELECT c.CategoryName, od2.UnitPrice, od2.Quantity,
         ROW_NUMBER() OVER(PARTITION BY c.CategoryName ORDER BY od2.UnitPrice * od2.Quantity DESC) AS rn
  FROM [Order Details] od JOIN Products p ON od.ProductID = p.ProductID
                          JOIN Categories c ON p.CategoryID = c.CategoryID
                          JOIN Orders o ON od.OrderID = o.OrderID
  WHERE o.OrderDate >= DATEADD(YEAR, DATEDIFF(YEAR, 0, '19970101'), 0)
    AND o.OrderDate < DATEADD(YEAR, DATEDIFF(YEAR, 0, '19970101')+1, 0)
  )
  SELECT CategoryName, SUM(UnitPrice * Quantity) AS val
  FROM cte
  WHERE rn < 6
  GROUP BY CategoryName

答案 2 :(得分:3)

这绝对是一个子查询问题,这里有一个excellent article(最初为Access编写但语法相同),orderdate = 1997也会给出1997年1月1日的订单日期 - 你需要datepart( year,orderdate)= 1997,一旦你为每个类别返回了(最多五行),你就可以封装返回的行并对它们进行重新集合

答案 3 :(得分:0)

我遇到了一个与Access子查询非常相似的问题,其中记录按日期排序。当我使用&#34; Last&#34;聚合函数我发现它通过所有子查询并从Access表中检索最后一行数据,而不是按预期检索排序查询。虽然我可以重写查询以在第一组括号中使用聚合函数(如前所述),但我发现将查询结果保存为数据库中按照我想要的顺序排序的表更容易,然后使用&# 34;最后&#34;用于检索我想要的值的聚合函数。我将来会运行更新查询以保持结果最新。不高效但有效。