DENSE_RANK 在两列上,其中一列是不同的值,另一列有重复
DENSE_RANK on two columns, where one column are distinct values and the other has duplicate
我有以下情况,我正在努力了解如何应用 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
根据上述数据,我尝试使用 Date
和 Value
列的组合来识别不同的时期,其中从 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
列上,因为我需要它作为一个累积周期。此外,周期的数量从 ID
到 ID
不等,并且 Date
列背后没有一致的科学依据。例如,一个成员可以在一年内有两个条目。
这被称为间隙和孤岛问题。一种方法是使用几个 ROW_NUMBER
将您的数据分组:
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;
您可以使用 LAG()
window 函数为每一行获取其先前的值,并使用 SUM()
window 函数的条件聚合获取 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。
我有以下情况,我正在努力了解如何应用 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 |
根据上述数据,我尝试使用 Date
和 Value
列的组合来识别不同的时期,其中从 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
列上,因为我需要它作为一个累积周期。此外,周期的数量从 ID
到 ID
不等,并且 Date
列背后没有一致的科学依据。例如,一个成员可以在一年内有两个条目。
这被称为间隙和孤岛问题。一种方法是使用几个 ROW_NUMBER
将您的数据分组:
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;
您可以使用 LAG()
window 函数为每一行获取其先前的值,并使用 SUM()
window 函数的条件聚合获取 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。