【问题标题】:DENSE_RANK on two columns, where one column are distinct values and the other has duplicate两列上的 DENSE_RANK,其中一列是不同的值,另一列是重复的
【发布时间】:2021-10-23 20:48:14
【问题描述】:

在以下情况下,我很难理解如何应用 DENSE_RANK() 来获得我想要的结果:

ID Date Value
1 1990-05-17 1.00
1 1991-10-12 1.00
1 1992-08-01 1.00
1 1993-07-05 0.67
1 1994-05-02 0.67
1 1995-02-01 1.00
1 1996-03-01 1.00

基于上述数据,我尝试使用DateValue 列的组合来识别不同的时期,其中一个独特的时期是从Value 列从一个值更改为另一个值的位置确定的.这是我正在寻找的结果:

ID Date Value Period
1 1990-05-17 1.00 1
1 1991-10-12 1.00 1
1 1992-08-01 1.00 1
1 1993-07-05 0.67 2
1 1994-05-02 0.67 2
1 1995-02-01 1.00 3
1 1996-03-01 1.00 3

如您所见,有 3 个不同的时期。我遇到的问题是,当我使用DENSE_RANK() 时,我会得到以下两种结果之一:

SELECT DENSE_RANK() OVER (PARTITION BY ID ORDER BY Date, Value)

ID Date Value Period
1 1990-05-17 1.00 1
1 1991-10-12 1.00 2
1 1992-08-01 1.00 3
1 1993-07-05 0.67 4
1 1994-05-02 0.67 5
1 1995-02-01 1.00 6
1 1996-03-01 1.00 7

SELECT DENSE_RANK() OVER (PARTITION BY ID ORDER BY Value)

ID Date Value Period
1 1990-05-17 1.00 1
1 1991-10-12 1.00 1
1 1992-08-01 1.00 1
1 1993-07-05 0.67 2
1 1994-05-02 0.67 2
1 1995-02-01 1.00 1
1 1996-03-01 1.00 1

如您所见,问题在于Date 列,因为我需要将其作为累积期。此外,句号的数量从IDID 不等,Date 列背后没有一致的科学依据。例如,一个成员在一年内可能有两个条目。

【问题讨论】:

    标签: sql-server sum window-functions dense-rank


    【解决方案1】:

    您可以使用LAG() 窗口函数为每一行获取其先前的值,并使用SUM() 窗口函数进行条件聚合获取Periods

    SELECT ID, Date, Value,
           SUM(CASE WHEN VALUE = prev_value THEN 0 ELSE 1 END) OVER (PARTITION BY ID ORDER BY Date) Period 
    FROM (
      SELECT *, LAG(Value) OVER (PARTITION BY ID ORDER BY Date) prev_value
      FROM tablename
    ) t
    ORDER BY Date;
    

    请参阅demo

    【讨论】:

      【解决方案2】:

      这被称为间隙和孤岛问题。一种方法是使用几个ROW_NUMBERs 将您的数据分组:

      
      WITH CTE AS(
          SELECT *,
                 ROW_NUMBER() OVER (PARTITION BY ID ORDER BY [date],[value])-
                 ROW_NUMBER() OVER (PARTITION BY ID, [value] ORDER BY [date]) AS Grp
          FROM (VALUES(1,CONVERT(date,'1990-05-17'),1.00),
                      (1,CONVERT(date,'1991-10-12'),1.00),
                      (1,CONVERT(date,'1992-08-01'),1.00),
                      (1,CONVERT(date,'1993-07-05'),0.67),
                      (1,CONVERT(date,'1994-05-02'),0.67),
                      (1,CONVERT(date,'1995-02-01'),1.00),
                      (1,CONVERT(date,'1996-03-01'),1.00))V(ID,Date,Value))
      SELECT ID,
             Date,
             Value,
             DENSE_RANK() OVER (PARTITION BY ID ORDER BY Grp) AS Period
      FROM CTE;
      

      【讨论】:

        猜你喜欢
        • 2019-05-25
        • 2023-03-09
        • 1970-01-01
        • 1970-01-01
        • 2019-05-26
        • 2016-05-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多