通过SQL审计表定位Location变更:解决自连接查询重复问题
问题描述
我在SQL数据库中有如下结构的audit table:
| audit_id | id | location | location_sub | location_status | dtm_utc_action | action_type |
|---|---|---|---|---|---|---|
| 2144 | 2105 | 9 | 1 | 1 | 2022-09-08 12:36 | i |
| 4653 | 2105 | 9 | 1 | 1 | 2022-09-08 13:53 | u |
| 7304 | 2105 | 10 | 2 | 2 | 2022-09-13 15:51 | u |
| 7326 | 2105 | 11 | 1 | 2 | 2022-09-14 10:06 | u |
需要编写查询语句,找出表中location发生变更的记录,展示id、旧location、新location以及变更时间。
我尝试过自连接查询,但会返回重复记录,不符合需求:
SELECT a.id, a.location AS old_loc, a.dtm_utc_action AS FirstModifyDate, b.location AS new_loc, b.dtm_utc_action AS SecondModifyDate FROM audit_table a JOIN audit_table b ON a.id = b.id WHERE a.audit_id <> b.audit_id AND a.dtm_utc_action < b.dtm_utc_action AND a.location <> b.location AND a.id = '2105'
期望结果格式:
| id | old_loc | new_loc | dtm_utc_action |
|---|---|---|---|
| 2105 | 9 | 10 | 2022-09-13 15:51 |
| 2105 | 10 | 11 | 2022-09-14 10:06 |
解决方案
要避免重复记录,关键是只关联每个id的相邻版本记录,可以用窗口函数LAG()获取上一条记录的location值,直接对比当前与上一条的location是否变更:
SELECT id, prev_location AS old_loc, location AS new_loc, dtm_utc_action FROM ( SELECT id, location, dtm_utc_action, -- 按id分组、操作时间排序,获取当前行的上一行location值 LAG(location) OVER (PARTITION BY id ORDER BY dtm_utc_action) AS prev_location FROM audit_table WHERE id = '2105' -- 若要查询所有id可去掉此条件 ) AS sub -- 过滤出location变更的记录,排除无前置记录的首行 WHERE prev_location IS NOT NULL AND prev_location <> location ORDER BY dtm_utc_action;
说明:
LAG(location) OVER (PARTITION BY id ORDER BY dtm_utc_action):按id分组、操作时间排序,提取当前行的上一行location值。- 子查询后过滤掉
prev_location为空的行(即第一条无旧值的记录),只保留前后location不同的行,得到每次变更的有效记录。 - 若需查询所有id的变更记录,删除
WHERE id = '2105'条件即可。
内容的提问来源于stack exchange,提问作者JstSomeGuy
相关产品推荐
相关产品推荐

