SQL窗口功能

SQL窗口功能,sql,sql-server,tsql,Sql,Sql Server,Tsql,我目前正在根据销售额的总和降序排序产品,并根据2007年每个产品的销售额总和排名,如果产品在该年的销售额最高,则排名第一,以此类推 目前,除了RankOf2008和DRankOf2008列之外,我的数据库表看起来与图中提到的一样,如果2007年前5名产品中的任何一款在2008年未售出,我想在2008年对2007年的前5名产品进行排名,如上图所示。您可能需要类似的产品 首先获取所有产品的排名,然后按年份进行划分,即按年度对产品进行排名,并借助CTE获取所需数据 SELECT *

我目前正在根据销售额的总和降序排序产品,并根据2007年每个产品的销售额总和排名,如果产品在该年的销售额最高,则排名第一,以此类推


目前,除了RankOf2008和DRankOf2008列之外,我的数据库表看起来与图中提到的一样,如果2007年前5名产品中的任何一款在2008年未售出,我想在2008年对2007年的前5名产品进行排名,如上图所示。您可能需要类似的产品

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

 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

在最里面的查询中使用条件聚合,即选择年份并有条件地求和其中一个年份:

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
但是SQLServer不符合这里的SQL标准,并且在ORDERBY子句中不具有NULL FIRST/LAST。幸运的是,当按降序排序时,它最后对null进行排序,因此它隐式地执行我们在这里想要的操作


顺便说一下:我们可以在一个步骤中进行聚合和排序,但在这种情况下,我们必须重复求和表达式。这是个人偏好的问题,是用一步较短的查询,还是两步不重复的表达。

谢谢您的反馈。这很有用
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;
rank() over (order by salesamount2008 desc nulls last) as rankof2008