您的问题(很遗憾)确实依赖于 db-engine。既然你标记了 Transact-SQL,那我就先在那里回答:
T-SQL 具有 SELECT TOP N 功能,允许获取前 N 行,如果它与 ORDER BY 子句耦合,它将首先排序并给你TOP N。如果您给它们起别名,Transact 还允许按聚合字段排序。
您的问题涉及两件事:物品和“顶级买家”;所以我们应该首先接触买家,因为他们是过滤器:
SELECT TOP 10 CustomerID, SUM(Price * Qty) as SumRevenue
FROM InvoiceTable
WHERE InvoiceDate between @StartDate, @EndDate
GROUP BY CustomerID
ORDER BY SumRevenue DESC
问题是,您想要此客户的项目列表。我会冒昧地猜测您想要这里每个客户每件商品的总收入,所以您现在需要使用它作为子查询来获取您的商品。我不会参与in vs inner join 的辩论,所以我只是举个例子:
SELECT r.CustomerID, r.ItemID, SUM(r.Price * r.Qty) ItemRevenue
FROM InvoiceTable
INNER JOIN (SELECT TOP 10 i.CustomerID, SUM(i.Price * i.Qty) as SumRevenue
FROM InvoiceTable i
WHERE i.InvoiceDate between @StartDate, @EndDate
GROUP BY i.CustomerID
ORDER BY SumRevenue DESC) s
ON r.CustomerID = s.CustomerID
WHERE r.InvoiceDate between @StartDate, @EndDate
GROUP BY r.CustomerID, r.ItemID
如果您使用 MYSQL,则 TOP N 习语将替换为 LIMIT N 习语,因此会导致:
SELECT r.CustomerID, r.ItemID, SUM(r.Price * r.Qty) ItemRevenue
FROM InvoiceTable
INNER JOIN (SELECT i.CustomerID, SUM(i.Price * i.Qty) as SumRevenue
FROM InvoiceTable i
WHERE i.InvoiceDate between @StartDate, @EndDate
GROUP BY i.CustomerID
ORDER BY SumRevenue DESC
LIMIT 10) s
ON r.CustomerID = s.CustomerID
WHERE r.InvoiceDate between @StartDate, @EndDate
GROUP BY r.CustomerID, r.ItemID
如果您使用 Oracle,查询会有点困难,因为您没有 TOP N 惯用语,而且您必须使用 ROWNUM 和子查询,所以我推荐一种类似的方法这个:
SELECT m.CustomerID, m.ItemID, m.ItemRevenue
(SELECT ROWNUM, r.CustomerID, r.ItemID, SUM(r.Price * r.Qty) ItemRevenue
FROM InvoiceTable
INNER JOIN (SELECT i.CustomerID, SUM(i.Price * i.Qty) as SumRevenue
FROM InvoiceTable i
WHERE i.InvoiceDate between @StartDate, @EndDate
GROUP BY i.CustomerID) s
ON r.CustomerID = s.CustomerID
WHERE r.InvoiceDate between @StartDate, @EndDate
GROUP BY r.CustomerID, r.ItemID
ORDER BY s.SumRevenue DESC) m
WHERE ROWNUM < 11