我有一个历史表,其中包含 id、日期和状态列。我试图识别 id 从状态 1(活动)更改为 0(非活动)并返回到 1(再次活动)的所有实例。我想创建一个数据透视表,其中所有不同的 id 作为行,所有日期作为列值。因为这是一个历史表,并且有大约 10M 个不同的 id,所以我试图看看什么是提取数据的理想/有效方法。
数据如下:
id date status
I01234 5/12/2023 1
I14690 4/13/2021 0
最终数据结构:
id 01/01/2021 01/02/2021 01/03/2021 ........ 10/31/2023
I01234 1 1 1 0
I14690 1 0 0 1
这将获取每个 id 从 active->inactive->active 移动的所有记录。请注意,这将拾取在任何时候具有此生命周期的记录,无论其当前状态如何。
还假设数据透视表不是必需的,我们只需要 ids/记录。
inactive_sandwich 子句中有两个主要条件。
第一个检查(通过 EXISTS)是否有该 id 的活动状态早于非活动状态的记录。
第二个是相同的想法,但检查活动记录晚于非活动记录的加载日期。
如果这两者都为真,则意味着您有一个较早的“活动”、一个“非活动”和一个较晚的“活动”。
此结果只会为您提供非活动记录,因此最后一个子句将选取与这些 id 关联的所有记录。
create table some_test_data
( id varchar(100),
status integer,
load_date date
)
insert into some_test_data values ('abc',1,cast('2023-01-01' as datetime));
insert into some_test_data values ('abc',0,cast('2023-01-02' as datetime));
insert into some_test_data values ('abc',1,cast('2023-01-03' as datetime));
insert into some_test_data values ('cde',1,cast('2023-01-04' as datetime));
insert into some_test_data values ('cde',1,cast('2023-01-05' as datetime));
insert into some_test_data values ('efg',1,cast('2023-01-05' as datetime));
insert into some_test_data values ('efg',0,cast('2023-01-05' as datetime));
with inactive_sandwich as (
select *
from some_test_data t1
where t1.status = 0
and exists
( select 1
from some_test_data earlier_active
where t1.id = earlier_active.id
and t1.load_date > earlier_active.load_date
and earlier_active.status = 1
)
and exists
( select 1
from some_test_data later_active
where t1.id = later_active.id
and t1.load_date < later_active.load_date
and later_active.status = 1
)
)
select *
from some_test_data t1
where exists
(
select 1
from inactive_sandwich t2
where t1.id = t2.id
)