两列上的 DENSE_RANK,其中一列是不同的值,另一列是重复的

Posted

技术标签:

【中文标题】两列上的 DENSE_RANK,其中一列是不同的值,另一列是重复的【英文标题】:DENSE_RANK on two columns, where one column are distinct values and the other has duplicate 【发布时间】: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 列背后没有一致的科学依据。例如,一个成员在一年内可能有两个条目。

【问题讨论】:

【参考方案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;

【讨论】:

以上是关于两列上的 DENSE_RANK,其中一列是不同的值,另一列是重复的的主要内容,如果未能解决你的问题,请参考以下文章

按两列分组,其中一列是时间戳

基于另一列中的值的一列上的pyspark滞后函数

索引列上的不同值

SQL - 插入两列,一列来自表,另一列是常量

使用条件删除数据框中一列上的重复值[重复]

jqxgrid 基于另一列上的值的可编辑属性