Sql 如何确定实体在多个数据库记录中是否一直处于活动状态?
示例数据集,其中每行记录一个独特的个人/专业组合的一段时间的有效时间段 注意:本示例数据集中显示了属于以下每个person_ID的所有记录 注2:终止日期9999/12/31仅表示此人目前正在该专业注册 最终目标数据集,其中有一个新的列,指示每个人是否在2017年全年连续注册专业Sql 如何确定实体在多个数据库记录中是否一直处于活动状态?,sql,oracle,Sql,Oracle,示例数据集,其中每行记录一个独特的个人/专业组合的一段时间的有效时间段 注意:本示例数据集中显示了属于以下每个person_ID的所有记录 注2:终止日期9999/12/31仅表示此人目前正在该专业注册 最终目标数据集,其中有一个新的列,指示每个人是否在2017年全年连续注册专业 TBL_MAJORS_2 Person_ID Major Effective_Date Termination_Date Active_Throughout_2017 76
TBL_MAJORS_2
Person_ID Major Effective_Date Termination_Date Active_Throughout_2017
76 Biology 2016/8/1 2017/2/24 1
76 Accounting 2017/2/25 2017/4/15 1
76 Math 2017/4/16 9999/12/31 1
102 Physics 2016/8/1 2018/7/21 1
58 Literature 2016/8/1 2017/5/13 0
94 Art History 2016/8/1 2017/8/30 0
94 Comp Sci 2018/3/1 9999/12/31 0
再解释一下
例如,76人有三个不同的专业,从2016年8月1日持续到9999年12月31日(即他们目前正在注册),因此他们在2017年持续注册
另一方面,94人有两个不同的专业,但从2017年8月31日到2018年2月28日,他们的活动存在差距,因此他们在2017年没有连续注册
有人能帮我做到这一点吗?如果你能让它表现得很好,你会得到额外的荣誉。。。我想这可能会涉及某种窗口/分析功能,但我真的被难倒了。可以这样做:
WITH tbl_majors AS (SELECT 76 person_id, 'Biology' major, to_date('01/08/2016', 'dd/mm/yyyy') effective_date, to_date('24/02/2017', 'dd/mm/yyyy') termination_date FROM dual UNION ALL
SELECT 76 person_id, 'Accounting' major, to_date('25/02/2017', 'dd/mm/yyyy') effective_date, to_date('15/04/2017', 'dd/mm/yyyy') termination_date FROM dual UNION ALL
SELECT 76 person_id, 'Math' major, to_date('16/04/2017', 'dd/mm/yyyy') effective_date, to_date('31/12/9999', 'dd/mm/yyyy') termination_date FROM dual UNION ALL
SELECT 102 person_id, 'Physics' major, to_date('01/08/2016', 'dd/mm/yyyy') effective_date, to_date('21/07/2018', 'dd/mm/yyyy') termination_date FROM dual UNION ALL
SELECT 58 person_id, 'Literature' major, to_date('01/08/2016', 'dd/mm/yyyy') effective_date, to_date('13/05/2017', 'dd/mm/yyyy') termination_date FROM dual UNION ALL
SELECT 94 person_id, 'Art History' major, to_date('01/08/2016', 'dd/mm/yyyy') effective_date, to_date('30/08/2017', 'dd/mm/yyyy') termination_date FROM dual UNION ALL
SELECT 94 person_id, 'Comp Sci' major, to_date('01/03/2018', 'dd/mm/yyyy') effective_date, to_date('31/12/9999', 'dd/mm/yyyy') termination_date FROM dual)
SELECT person_id,
major,
effective_date,
termination_date,
CASE WHEN to_date('01/01/2017', 'dd/mm/yyyy') >= MIN(effective_date) OVER (PARTITION BY person_id, grp)
AND to_date('31/12/2017', 'dd/mm/yyyy') <= MAX(termination_date) OVER (PARTITION BY person_id, grp)
THEN 1
ELSE 0
END active_throughout_2017
FROM (SELECT person_id,
major,
effective_date,
termination_date,
SUM(new_grp_start) OVER (PARTITION BY person_id ORDER BY effective_date) grp
FROM (SELECT person_id,
major,
effective_date,
termination_date,
CASE WHEN effective_date = LAG(termination_date) OVER (PARTITION BY person_id ORDER BY effective_date) + 1 THEN 0 ELSE 1 END new_grp_start
FROM tbl_majors));
PERSON_ID MAJOR EFFECTIVE_DATE TERMINATION_DATE ACTIVE_THROUGHOUT_2017
---------- ----------- -------------- ---------------- ----------------------
58 Literature 01/08/2016 13/05/2017 0
76 Accounting 25/02/2017 15/04/2017 1
76 Biology 01/08/2016 24/02/2017 1
76 Math 16/04/2017 31/12/9999 1
94 Art History 01/08/2016 30/08/2017 0
94 Comp Sci 01/03/2018 31/12/9999 0
102 Physics 01/08/2016 21/07/2018 1
正如您所看到的,它比我原来的解决方案优雅得多。您应该测试这两种方法,看看哪一种对您的数据更有效,等等
两种解决方案都假设不会有重叠(即,学生在任何时候都只会有一个专业);您必须相应地调整它们,以适应某个人一次可能拥有多个专业的情况。可以这样做:
WITH tbl_majors AS (SELECT 76 person_id, 'Biology' major, to_date('01/08/2016', 'dd/mm/yyyy') effective_date, to_date('24/02/2017', 'dd/mm/yyyy') termination_date FROM dual UNION ALL
SELECT 76 person_id, 'Accounting' major, to_date('25/02/2017', 'dd/mm/yyyy') effective_date, to_date('15/04/2017', 'dd/mm/yyyy') termination_date FROM dual UNION ALL
SELECT 76 person_id, 'Math' major, to_date('16/04/2017', 'dd/mm/yyyy') effective_date, to_date('31/12/9999', 'dd/mm/yyyy') termination_date FROM dual UNION ALL
SELECT 102 person_id, 'Physics' major, to_date('01/08/2016', 'dd/mm/yyyy') effective_date, to_date('21/07/2018', 'dd/mm/yyyy') termination_date FROM dual UNION ALL
SELECT 58 person_id, 'Literature' major, to_date('01/08/2016', 'dd/mm/yyyy') effective_date, to_date('13/05/2017', 'dd/mm/yyyy') termination_date FROM dual UNION ALL
SELECT 94 person_id, 'Art History' major, to_date('01/08/2016', 'dd/mm/yyyy') effective_date, to_date('30/08/2017', 'dd/mm/yyyy') termination_date FROM dual UNION ALL
SELECT 94 person_id, 'Comp Sci' major, to_date('01/03/2018', 'dd/mm/yyyy') effective_date, to_date('31/12/9999', 'dd/mm/yyyy') termination_date FROM dual)
SELECT person_id,
major,
effective_date,
termination_date,
CASE WHEN to_date('01/01/2017', 'dd/mm/yyyy') >= MIN(effective_date) OVER (PARTITION BY person_id, grp)
AND to_date('31/12/2017', 'dd/mm/yyyy') <= MAX(termination_date) OVER (PARTITION BY person_id, grp)
THEN 1
ELSE 0
END active_throughout_2017
FROM (SELECT person_id,
major,
effective_date,
termination_date,
SUM(new_grp_start) OVER (PARTITION BY person_id ORDER BY effective_date) grp
FROM (SELECT person_id,
major,
effective_date,
termination_date,
CASE WHEN effective_date = LAG(termination_date) OVER (PARTITION BY person_id ORDER BY effective_date) + 1 THEN 0 ELSE 1 END new_grp_start
FROM tbl_majors));
PERSON_ID MAJOR EFFECTIVE_DATE TERMINATION_DATE ACTIVE_THROUGHOUT_2017
---------- ----------- -------------- ---------------- ----------------------
58 Literature 01/08/2016 13/05/2017 0
76 Accounting 25/02/2017 15/04/2017 1
76 Biology 01/08/2016 24/02/2017 1
76 Math 16/04/2017 31/12/9999 1
94 Art History 01/08/2016 30/08/2017 0
94 Comp Sci 01/03/2018 31/12/9999 0
102 Physics 01/08/2016 21/07/2018 1
正如您所看到的,它比我原来的解决方案优雅得多。您应该测试这两种方法,看看哪一种对您的数据更有效,等等
两种解决方案都假设不会有重叠(即,学生在任何时候都只会有一个专业);您必须相应地调整它们,以适应可能有人同时拥有多个专业的情况。好吧,我可以给您一个提示-对于每个记录,计算2017年内每个人注册的天数。然后将其汇总并加入原始表,检查2017年登记的总天数是否等于2017年的总天数。哦,这太好了,应该可以与我的实际数据集很好地配合。谢谢你提出了这个有用的想法。也许你的答案就在这里:好吧,我可以给你一个提示——对于每个记录,计算2017年内每个人注册的天数。然后将其汇总并加入原始表,检查2017年登记的总天数是否等于2017年的总天数。哦,这太好了,应该可以与我的实际数据集很好地配合。谢谢你的建议。也许你的答案就在这里:非常感谢。你是我这一天的英雄。不过,我要说的是,GSazheniuk总结2017年的想法比我的答案更优雅、更简单,也更有可能更有效!非常感谢你。你是我这一天的英雄。不过,我要说的是,GSazheniuk总结2017年的想法比我的答案更优雅、更简单,也更有可能更有效!
WITH tbl_majors AS (SELECT 76 person_id, 'Biology' major, to_date('01/08/2016', 'dd/mm/yyyy') effective_date, to_date('24/02/2017', 'dd/mm/yyyy') termination_date FROM dual UNION ALL
SELECT 76 person_id, 'Accounting' major, to_date('25/02/2017', 'dd/mm/yyyy') effective_date, to_date('15/04/2017', 'dd/mm/yyyy') termination_date FROM dual UNION ALL
SELECT 76 person_id, 'Math' major, to_date('16/04/2017', 'dd/mm/yyyy') effective_date, to_date('31/12/9999', 'dd/mm/yyyy') termination_date FROM dual UNION ALL
SELECT 102 person_id, 'Physics' major, to_date('01/08/2016', 'dd/mm/yyyy') effective_date, to_date('21/07/2018', 'dd/mm/yyyy') termination_date FROM dual UNION ALL
SELECT 58 person_id, 'Literature' major, to_date('01/08/2016', 'dd/mm/yyyy') effective_date, to_date('13/05/2017', 'dd/mm/yyyy') termination_date FROM dual UNION ALL
SELECT 94 person_id, 'Art History' major, to_date('01/08/2016', 'dd/mm/yyyy') effective_date, to_date('30/08/2017', 'dd/mm/yyyy') termination_date FROM dual UNION ALL
SELECT 94 person_id, 'Comp Sci' major, to_date('01/03/2018', 'dd/mm/yyyy') effective_date, to_date('31/12/9999', 'dd/mm/yyyy') termination_date FROM dual)
SELECT person_id,
major,
effective_date,
termination_date,
CASE WHEN SUM(LEAST(to_date('31/12/2017', 'dd/mm/yyyy'), termination_date) + 1 - GREATEST(to_date('01/01/2017', 'dd/mm/yyyy'), effective_date)) OVER (PARTITION BY person_id)
= to_date('31/12/2017', 'dd/mm/yyyy') + 1 - to_date('01/01/2017', 'dd/mm/yyyy')
THEN 1
ELSE 0
END active_throughout_2017
FROM tbl_majors;