对具有复发历史的数据进行排序
Rank data with history of recurrence
假设我正在跟踪用户的位置,并且捕获了以下信息:
- 日期
- 用户 ID
- 当前位置
我可以对这些数据进行相当简单的转换以形成一个新的 table 以获得他们最后的已知位置(如果存在的话),我将在下面包含它以向我们展示从一个点移动到另一个点.
我想为每个用户的当前位置创建一个分组,并在他们的位置从以前的值发生变化时增加它。如果用户离开某个位置,然后又回到该位置,我希望将其视为一个新值,而不是在他们第一次到达该位置时将其与组混为一谈。
使用 RANK 或 DENSE_RANK 执行此操作的问题是我按 currentPos 排序,这显然行不通。
我想我可以使用 LAG() 查看以前的数据,但这不允许您将以前记录的 LAG() 与当前行聚合。
这是一个使用 RANK()
的例子
WITH dummyData(id, occuredOn, userId, currentPos, lastPos) AS (
SELECT 01, '2021-01-01 00:00:00', 23, 'A', null
UNION ALL
SELECT 22, '2021-01-01 01:30:00', 23, 'A', 'A'
UNION ALL
SELECT 43, '2021-01-01 04:00:00', 23, 'B', 'A'
UNION ALL
SELECT 55, '2021-01-02 00:00:00', 23, 'C', 'B'
UNION ALL
SELECT 59, '2021-01-02 04:40:00', 23, 'B', 'C'
UNION ALL
SELECT 68, '2021-01-02 08:00:00', 23, 'C', 'B'
UNION ALL
SELECT 69, '2021-01-02 09:00:00', 23, 'D', 'C'
UNION ALL
SELECT 11, '2021-01-01 01:00:00', 43, 'X', 'X'
UNION ALL
SELECT 18, '2021-01-01 02:00:00', 43, 'Y', 'X'
UNION ALL
SELECT 32, '2021-01-02 00:00:00', 43, 'Z', 'Y'
)
SELECT *
, DENSE_RANK() OVER (PARTITION BY userId ORDER BY currentPos) locationChangeGroup
FROM dummyData
ORDER BY userId ASC, occuredOn ASC
这是它的输出
id
occurredOn
userId
currentPos
lastPos
locationChangeGroup
01
2021-01-01 00:00:00
23
A
NULL
1
22
2021-01-01 01:30:00
23
A
A
1
43
2021-01-01 04:00:00
23
B
A
2
55
2021-01-02 00:00:00
23
C
B
3
59
2021-01-02 04:40:00
23
B
C
2
68
2021-01-02 08:00:00
23
C
B
3
69
2021-01-02 09:00:00
23
D
C
4
11
2021-01-01 01:00:00
43
X
X
1
18
2021-01-01 02:00:00
43
Y
X
2
32
2021-01-02 00:00:00
43
Z
Y
3
这就是我想要的
id
occurredOn
userId
currentPos
lastPos
locationChangeGroup
01
2021-01-01 00:00:00
23
A
NULL
1
22
2021-01-01 01:30:00
23
A
A
1
43
2021-01-01 04:00:00
23
B
A
2
55
2021-01-02 00:00:00
23
C
B
3
59
2021-01-02 04:40:00
23
B
C
4
68
2021-01-02 08:00:00
23
C
B
5
69
2021-01-02 09:00:00
23
D
C
6
11
2021-01-01 01:00:00
43
X
X
1
18
2021-01-01 02:00:00
43
Y
X
2
32
2021-01-02 00:00:00
43
Z
Y
3
我知道我可以使用 CURSOR 来做到这一点,但我不想求助于它。
T-SQL 很好,但我试图远离任何存储的过程或函数,因为它需要更大的努力来生成数据库迁移脚本和我们流程的繁琐程序.
有什么建议吗?
我认为这是一个间隙和孤岛问题。为此,您可以使用 lag()
和累计总和:
select dd.*,
sum(case when prev_currentpos = currentpos then 0 else 1 end) over
(partition by userid
order by occurredon
) as locationChangeGroup
from (select dd.*,
lag(currentpos) over (partition by userid order by occurredon) as prev_currentpos
from dummydata dd
) dd
假设我正在跟踪用户的位置,并且捕获了以下信息:
- 日期
- 用户 ID
- 当前位置
我可以对这些数据进行相当简单的转换以形成一个新的 table 以获得他们最后的已知位置(如果存在的话),我将在下面包含它以向我们展示从一个点移动到另一个点.
我想为每个用户的当前位置创建一个分组,并在他们的位置从以前的值发生变化时增加它。如果用户离开某个位置,然后又回到该位置,我希望将其视为一个新值,而不是在他们第一次到达该位置时将其与组混为一谈。
使用 RANK 或 DENSE_RANK 执行此操作的问题是我按 currentPos 排序,这显然行不通。
我想我可以使用 LAG() 查看以前的数据,但这不允许您将以前记录的 LAG() 与当前行聚合。
这是一个使用 RANK()
的例子WITH dummyData(id, occuredOn, userId, currentPos, lastPos) AS (
SELECT 01, '2021-01-01 00:00:00', 23, 'A', null
UNION ALL
SELECT 22, '2021-01-01 01:30:00', 23, 'A', 'A'
UNION ALL
SELECT 43, '2021-01-01 04:00:00', 23, 'B', 'A'
UNION ALL
SELECT 55, '2021-01-02 00:00:00', 23, 'C', 'B'
UNION ALL
SELECT 59, '2021-01-02 04:40:00', 23, 'B', 'C'
UNION ALL
SELECT 68, '2021-01-02 08:00:00', 23, 'C', 'B'
UNION ALL
SELECT 69, '2021-01-02 09:00:00', 23, 'D', 'C'
UNION ALL
SELECT 11, '2021-01-01 01:00:00', 43, 'X', 'X'
UNION ALL
SELECT 18, '2021-01-01 02:00:00', 43, 'Y', 'X'
UNION ALL
SELECT 32, '2021-01-02 00:00:00', 43, 'Z', 'Y'
)
SELECT *
, DENSE_RANK() OVER (PARTITION BY userId ORDER BY currentPos) locationChangeGroup
FROM dummyData
ORDER BY userId ASC, occuredOn ASC
这是它的输出
id | occurredOn | userId | currentPos | lastPos | locationChangeGroup |
---|---|---|---|---|---|
01 | 2021-01-01 00:00:00 | 23 | A | NULL | 1 |
22 | 2021-01-01 01:30:00 | 23 | A | A | 1 |
43 | 2021-01-01 04:00:00 | 23 | B | A | 2 |
55 | 2021-01-02 00:00:00 | 23 | C | B | 3 |
59 | 2021-01-02 04:40:00 | 23 | B | C | 2 |
68 | 2021-01-02 08:00:00 | 23 | C | B | 3 |
69 | 2021-01-02 09:00:00 | 23 | D | C | 4 |
11 | 2021-01-01 01:00:00 | 43 | X | X | 1 |
18 | 2021-01-01 02:00:00 | 43 | Y | X | 2 |
32 | 2021-01-02 00:00:00 | 43 | Z | Y | 3 |
这就是我想要的
id | occurredOn | userId | currentPos | lastPos | locationChangeGroup |
---|---|---|---|---|---|
01 | 2021-01-01 00:00:00 | 23 | A | NULL | 1 |
22 | 2021-01-01 01:30:00 | 23 | A | A | 1 |
43 | 2021-01-01 04:00:00 | 23 | B | A | 2 |
55 | 2021-01-02 00:00:00 | 23 | C | B | 3 |
59 | 2021-01-02 04:40:00 | 23 | B | C | 4 |
68 | 2021-01-02 08:00:00 | 23 | C | B | 5 |
69 | 2021-01-02 09:00:00 | 23 | D | C | 6 |
11 | 2021-01-01 01:00:00 | 43 | X | X | 1 |
18 | 2021-01-01 02:00:00 | 43 | Y | X | 2 |
32 | 2021-01-02 00:00:00 | 43 | Z | Y | 3 |
我知道我可以使用 CURSOR 来做到这一点,但我不想求助于它。
T-SQL 很好,但我试图远离任何存储的过程或函数,因为它需要更大的努力来生成数据库迁移脚本和我们流程的繁琐程序.
有什么建议吗?
我认为这是一个间隙和孤岛问题。为此,您可以使用 lag()
和累计总和:
select dd.*,
sum(case when prev_currentpos = currentpos then 0 else 1 end) over
(partition by userid
order by occurredon
) as locationChangeGroup
from (select dd.*,
lag(currentpos) over (partition by userid order by occurredon) as prev_currentpos
from dummydata dd
) dd