SQL窗口排序功能

时间:2019-02-15 09:23:53

标签: sql sql-server tsql

 SELECT
        *
    FROM (
        SELECT 

            Product,
            SalesAmount,
            ROW_NUMBER() OVER (ORDER BY SalesAmount DESC) as RowNum,
            RANK() OVER (ORDER BY SalesAmount DESC) as RankOf2007,
            DENSE_RANK() OVER (ORDER BY SalesAmount DESC) as DRankOf2007
        FROM (
            SELECT

                c.EnglishProductName as Product,
                SUM(a.SalesAmount) as SalesAmount,
                b.CalendarYear as CalenderYear
            FROM FactInternetSales a
            INNER JOIN DimDate b
                ON  a.OrderDateKey=b.DateKey
            INNER JOIN DimProduct c
                ON  a.ProductKey=c.ProductKey

            WHERE   b.CalendarYear IN (2007)
            GROUP BY c.EnglishProductName,b.CalendarYear
            ) Sales
        ) Rankings
    WHERE [RankOf2007] <= 5
    ORDER BY [SalesAmount] DESC

我目前正在根据销售额的总和对产品进行降序排序,并根据2007年每种产品的总销售额进行排名,如果产品1当年销售额最高,则将其排名为1等。

My Database data's image

当前,我的数据库表看起来像图像中提到的那样(除了RankOf2008和DRankOf2008列),我希望在2008年中对2007年的前5名产品进行排名(如果前5名产品中的任何5个产品,则为空值)如上图所示,在同一表格中并排排列着2007年的2007年未售出的价格。

2 个答案:

答案 0 :(得分:1)

也许您需要这样的东西。

首先获得所有产品的排名,然后按年份进行划分,即按年度对产品进行排名,并在CTE的帮助下获取所需数据。

WITH cte
AS (
    SELECT *
    FROM (
        SELECT Product
            ,SalesAmount
            ,CalenderYear
            ,ROW_NUMBER() OVER (
                PARTITION BY CalenderYear ORDER BY SalesAmount DESC
                ) AS RowNum
            ,RANK() OVER (
                PARTITION BY CalenderYear ORDER BY SalesAmount DESC
                ) AS RankOf2007
            ,DENSE_RANK() OVER (
                PARTITION BY CalenderYear ORDER BY SalesAmount DESC
                ) AS DRankOf2007
        FROM (
            SELECT c.EnglishProductName AS Product
                ,SUM(a.SalesAmount) AS SalesAmount
                ,b.CalendarYear AS CalenderYear
            FROM FactInternetSales a
            INNER JOIN DimDate b ON a.OrderDateKey = b.DateKey
            INNER JOIN DimProduct c ON a.ProductKey = c.ProductKey
            --WHERE b.CalendarYear IN (2007)
            GROUP BY c.EnglishProductName
                ,b.CalendarYear
            ) Sales
        ) Rankings
        --WHERE [RankOf2007] <= 5
        --ORDER BY [SalesAmount] DESC
    )
SELECT a.*
    ,b.DRankOf2007 AS [DRankOf2008]
    ,b.RankOf2007 AS [RankOf2008]
FROM cte a
LEFT JOIN cte b ON a.Product = b.Product
    AND b.CalenderYear = 2008
WHERE a.CalenderYear = 2007
    AND a.[RankOf2007] <= 5

答案 1 :(得分:0)

在最里面的查询中使用条件汇总(即,选择年份和有条件地合计年份之一):

select
  p.productkey,
  p.englishproductname as product,
  ranked.salesamount2007,
  ranked.salesamount2008,
  ranked.rankof2007,
  ranked.rankof2008
from
(
  select
    productkey,
    salesamount2007,
    salesamount2008,
    rank() over (order by salesamount2007 desc) as rankof2007,
    rank() over (order by salesamount2008 desc) as rankof2008
  from
  (
    select
      s.productkey,
      sum(case when d.calendaryear = 2007 then s.salesamount end) as salesamount2007,
      sum(case when d.calendaryear = 2008 then s.salesamount end) as salesamount2008
    from factinternetsales s
    inner join dimdate d on d.datekey = s.orderdatekey
    where d.calendaryear in (2007, 2008)
    group by s.productkey
  ) aggregated
) ranked
join dimproduct p on p.productkey = ranked.productkey
where ranked.rankof2007 <= 5
order by ranked.rankof2007 desc;

对于2008年没有产品行的情况,salesamount2008将为空。在标准SQL中,我们将在ORDER BY子句中考虑这一点:

rank() over (order by salesamount2008 desc nulls last) as rankof2008

但是SQL Server不符合此处的SQL标准,并且在NULLS FIRST/LAST子句中不具有ORDER BY。幸运的是,当按降序排序时,它将最后排序空值,因此它隐式地执行了我们在这里想要的操作。

顺便说一句:我们可以在一个步骤中进行汇总和排名,但是在这种情况下,我们必须重复SUM表达式。是一步一步(较短的查询)还是一步一步(无重复的表达式)来完成此操作。