Reputation: 7201
I need to return the top 10 products per year, how can I do this with my following query?
SELECT
DP.ProductID
, DP.Name
, Year(FS.OrderDate) as TheYear
, FS.OrderQty
, FS.OrderAmount
FROM dbo.DimProduct AS DP
LEFT JOIN dbo.FactSales as FS on FS.ProductID = DP.ProductID
Upvotes: 2
Views: 2400
Reputation: 3911
SELECT
DP.ProductID
, DP.Name
, Year(FS.OrderDate) as TheYear
, FS.OrderQty
, FS.OrderAmount
, (FS.OrderQty * FS.OrderAmount) AS FS.Total
FROM dbo.DimProduct AS DP
LEFT JOIN dbo.FactSales as FS on FS.ProductID = DP.ProductID
GROUP BY TheYear, DP.ProductID, FS.Total
ORDER BY FS.Total DESC
WHERE seqnum <= 10;
Upvotes: 0
Reputation: 263763
This should be easy if your RDBMS supports Window Functions
SELECT ProductID,
Name,
TheYear,
OrderQty,
OrderAmount
FROM
(
SELECT DP.ProductID
,DP.Name
,Year(FS.OrderDate) as TheYear
,FS.OrderQty
,FS.OrderAmount,
,ROW_NUMBER() OVER() (PARTITION BY Year(FS.OrderDate)
ORDER BY FS.OrderQty DESC) rn
FROM dbo.DimProduct AS DP
LEFT JOIN dbo.FactSales as FS
on FS.ProductID = DP.ProductID
) s
WHERE rn <= 10
ORDER BY TheYear
The current query will give you 10
products for every TheYear
based on FS.OrderQty
since you have not mentioned the criteria on how the records will be sorted out.
The ROW_NUMBER()
(a RANKING function) will generate a sequence of number for each group, in this case Year(FS.OrderDate)
, that is sorted out based on FS.OrderQty
. The records will then be filtered out based on the value of the generated sequence.
However, if ROW_NUMBER()
will not generate TIE
on the records having the same FS.OrderQty
. If you want it to be handled, use DENSE_RANK()
instead of ROW_NUMBER()
.
Upvotes: 3
Reputation: 1270181
You want to use the function row_number()
to get the top 10. This assumes that OrderQty
defines the top 10:
select t.*
from (SELECT DP.ProductID, DP.Name, Year(FS.OrderDate) as TheYear, FS.OrderQty, FS.OrderAmount,
row_number() over (partition by Year(FS.OrderDate)
order by fs.OrderAmount desc
) as seqnum
FROM dbo.DimProduct DP LEFT JOIN
dbo.FactSales FS
on FS.ProductID = DP.ProductID
) t
where seqnum <= 10;
The function row_number()
enumerates rows, starting with 1. It starts over within each group, as defined by the partition by
clause (in your case, the year). The ordering of the numbers is based on the order by
clause (in your case, fs.OrderAmount desc
). So, the ten best products in each year will have the numbers 1-10 and the where
clause just chooses them.
Upvotes: 3