在每个 id 的空值之后查找第一次出现
Finding the first occurrence after a null value for each id
有两个表:A) 时间范围内的所有有效日期 B) 事件 ID 列表和事件发生的相应日期。
dt_util
2022-05-01
2022-05-02
2022-05-04
2022-05-05
2022-05-06
2022-05-07
id_event
dt_event
1
2022-05-01
2
2022-05-01
3
2022-05-01
1
2022-05-02
3
2022-05-02
1
2022-05-04
2
2022-05-04
3
2022-05-04
1
2022-05-05
2
2022-05-05
1
2022-05-07
2
2022-05-07
期望的结果是为每个 ID 找到最后一个“缺失”(NULL) 日期之后的最小日期,如下所示:
id_event
min_dt_event
1
2022-05-07
2
2022-05-07
3
2022-05-01
我一直在尝试使用 FIRST_VALUE 和 ROW_NUMBER,但到目前为止运气不好。我知道这两个表可能都经过一个循环,但是对于真实的数据集来说这是不可行的。
-- Creating temp tables
DROP TABLE IF EXISTS #TEMP_EVENTS
DROP TABLE IF EXISTS #TEMP_DATES
CREATE TABLE #TEMP_EVENTS (
id_event smallint,
dt_event date
)
CREATE TABLE #TEMP_DATES (
dt_util date
)
INSERT INTO #TEMP_EVENTS VALUES
(1, '2022-05-01'),
(2, '2022-05-01'),
(3, '2022-05-01'),
(1, '2022-05-02'),
(3, '2022-05-02'),
(1, '2022-05-04'),
(2, '2022-05-04'),
(3, '2022-05-04'),
(1, '2022-05-05'),
(2, '2022-05-05'),
(1, '2022-05-07'),
(2, '2022-05-07')
INSERT INTO #TEMP_DATES VALUES
('2022-05-01'),
('2022-05-02'),
('2022-05-04'),
('2022-05-05'),
('2022-05-06'),
('2022-05-07')
-- Creating fictional table where all ids matches all dates
DROP TABLE IF EXISTS #TEMP_ID_EVENTS
SELECT DISTINCT ID_EVENT, DT_UTIL
INTO #TEMP_ALL_DATES
FROM #TEMP_EVENTS A
LEFT JOIN #TEMP_DATES B
ON 1 = 1
-- Minimum date after a null date
SELECT
A.ID_EVENT, [DT_UTIL], [DT_EVENT],
FIRST_VALUE([DT_UTIL]) OVER (PARTITION BY A.[ID_EVENT] ORDER BY [DT_EVENT] DESC) AS MIN_DATE
FROM
#TEMP_ALL_DATES A
LEFT JOIN
#TEMP_EVENTS B
ON
A.id_event = B.id_event
AND A.dt_util = B.dt_event
WHERE dt_event IS NULL
sub-query 使用 row_number()
为 #TEMP_DATES
中的日期生成 运行 数字。
然后加入 date
上的那个 sub-query 并使用 lag()
检查 row_number rn
,如果没有任何缺失,它应该与 1 不同日期。
最后只需获取 max
即可获取“最后缺失的空值”的日期
with cte as
(
select *,
flag = case when d.rn <> 1
and lag(d.rn) over(partition by e.id_event
order by e.dt_event) <> d.rn - 1
then 1
else 0
end
from #TEMP_EVENTS e
inner join
(
select rn = row_number() over (order by dt_util),
dt_util
from #TEMP_DATES
) d on e.dt_event = d.dt_util
)
select id_event,
dt_event = max(case when flag = 1 then dt_event end)
from cte
group by id_event
结果:
id_event
dt_event
1
2022-05-07
2
2022-05-07
3
null
有两个表:A) 时间范围内的所有有效日期 B) 事件 ID 列表和事件发生的相应日期。
dt_util |
---|
2022-05-01 |
2022-05-02 |
2022-05-04 |
2022-05-05 |
2022-05-06 |
2022-05-07 |
id_event | dt_event |
---|---|
1 | 2022-05-01 |
2 | 2022-05-01 |
3 | 2022-05-01 |
1 | 2022-05-02 |
3 | 2022-05-02 |
1 | 2022-05-04 |
2 | 2022-05-04 |
3 | 2022-05-04 |
1 | 2022-05-05 |
2 | 2022-05-05 |
1 | 2022-05-07 |
2 | 2022-05-07 |
期望的结果是为每个 ID 找到最后一个“缺失”(NULL) 日期之后的最小日期,如下所示:
id_event | min_dt_event |
---|---|
1 | 2022-05-07 |
2 | 2022-05-07 |
3 | 2022-05-01 |
我一直在尝试使用 FIRST_VALUE 和 ROW_NUMBER,但到目前为止运气不好。我知道这两个表可能都经过一个循环,但是对于真实的数据集来说这是不可行的。
-- Creating temp tables
DROP TABLE IF EXISTS #TEMP_EVENTS
DROP TABLE IF EXISTS #TEMP_DATES
CREATE TABLE #TEMP_EVENTS (
id_event smallint,
dt_event date
)
CREATE TABLE #TEMP_DATES (
dt_util date
)
INSERT INTO #TEMP_EVENTS VALUES
(1, '2022-05-01'),
(2, '2022-05-01'),
(3, '2022-05-01'),
(1, '2022-05-02'),
(3, '2022-05-02'),
(1, '2022-05-04'),
(2, '2022-05-04'),
(3, '2022-05-04'),
(1, '2022-05-05'),
(2, '2022-05-05'),
(1, '2022-05-07'),
(2, '2022-05-07')
INSERT INTO #TEMP_DATES VALUES
('2022-05-01'),
('2022-05-02'),
('2022-05-04'),
('2022-05-05'),
('2022-05-06'),
('2022-05-07')
-- Creating fictional table where all ids matches all dates
DROP TABLE IF EXISTS #TEMP_ID_EVENTS
SELECT DISTINCT ID_EVENT, DT_UTIL
INTO #TEMP_ALL_DATES
FROM #TEMP_EVENTS A
LEFT JOIN #TEMP_DATES B
ON 1 = 1
-- Minimum date after a null date
SELECT
A.ID_EVENT, [DT_UTIL], [DT_EVENT],
FIRST_VALUE([DT_UTIL]) OVER (PARTITION BY A.[ID_EVENT] ORDER BY [DT_EVENT] DESC) AS MIN_DATE
FROM
#TEMP_ALL_DATES A
LEFT JOIN
#TEMP_EVENTS B
ON
A.id_event = B.id_event
AND A.dt_util = B.dt_event
WHERE dt_event IS NULL
sub-query 使用 row_number()
为 #TEMP_DATES
中的日期生成 运行 数字。
然后加入 date
上的那个 sub-query 并使用 lag()
检查 row_number rn
,如果没有任何缺失,它应该与 1 不同日期。
最后只需获取 max
即可获取“最后缺失的空值”的日期
with cte as
(
select *,
flag = case when d.rn <> 1
and lag(d.rn) over(partition by e.id_event
order by e.dt_event) <> d.rn - 1
then 1
else 0
end
from #TEMP_EVENTS e
inner join
(
select rn = row_number() over (order by dt_util),
dt_util
from #TEMP_DATES
) d on e.dt_event = d.dt_util
)
select id_event,
dt_event = max(case when flag = 1 then dt_event end)
from cte
group by id_event
结果:
id_event | dt_event |
---|---|
1 | 2022-05-07 |
2 | 2022-05-07 |
3 | null |