每年返回前10名

时间:2013-05-31 13:11:37

标签: sql tsql greatest-n-per-group

我需要每年退回十大产品,我如何通过以下查询来完成这项工作?

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

3 个答案:

答案 0 :(得分:3)

如果您的RDBMS支持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

当前查询会根据10为每TheYearFS.OrderQty个产品提供ROW_NUMBER()个产品,因为您没有提及有关如何整理记录的条件。

Year(FS.OrderDate) a RANKING函数)将为每个组生成一个数字序列,在本例中为FS.OrderQty,根据{{1}进行整理}。然后将根据生成的序列的值过滤掉记录。


但是,如果ROW_NUMBER()不会在具有相同TIE的记录上生成FS.OrderQty。如果您希望对其进行处理,请使用DENSE_RANK()代替ROW_NUMBER()

答案 1 :(得分:3)

您希望使用函数row_number()获得前10名。这假设OrderQty定义了前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;

函数row_number()枚举行,从1开始。它在每个组中重新开始,由partition by子句(在您的情况下为年份)定义。数字的排序基于order by子句(在您的情况下为fs.OrderAmount desc)。因此,每年十个最佳产品的数字为1-10,而where条款只选择它们。

答案 2 :(得分:0)

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;