我在创建Oracle SQL语句时遇到了一个两难的问题,需要满足以下要求:
假设我在PROD_TABLE中有这些记录。
*PROD_TABLE
分配ID | 生效开始日期 | 有效结束日期 | 行动原因 |
---|---|---|---|
一千零一 | 2010年1月1日 | 2015年2月2日 | 名称变更 |
一千零一 | 2015年3月2日 | 2021年5月5日 | 名称变更 |
一千零一 | 2021年5月6日 | 2023年3月3日 | 名称变更 |
一千零一 | 2023年3月4日 | 12/31/4712 | 名称变更 |
假设我在STAGING_TABLE中有这些记录。
STAGING_TABLE
分配ID | 生效开始日期 | 有效结束日期 | 行动原因 |
---|---|---|---|
一千零一 | 2015年3月2日 | 2021年5月5日 | 部门变更 |
一千零一 | 2021年5月6日 | 12/31/4712 | 经理变更 |
**逻辑将如下...**这些记录将保持不变。仅ACTION_REASON字段将被更新(基于STAGING_TABLE.ACTION_REASON字段的更新)。
分配ID | 生效开始日期 | 有效结束日期 | 行动原因 |
---|---|---|---|
一千零一 | 2010年1月1日 | 2015年2月2日 | 名称变更 |
一千零一 | 2015年3月2日 | 2021年5月5日 | 部门变更 |
将删除PROD_TABLE中的这些记录,因为日期范围在STAGING_TABLE中重叠。
| 分配ID|生效开始日期|有效结束日期|行动原因|
| --------------|--------------|--------------|--------------|
| 一千零一|2021年5月6日|2023年3月3日|名称变更|
| 一千零一|2023年3月4日|12/31/4712|名称变更|
重叠的日期范围将根据STAGING_TABLE中的日期范围进行更改。
| 分配ID|生效开始日期|有效结束日期|行动原因|
| --------------|--------------|--------------|--------------|
| 一千零一|2021年5月6日|12/31/4712|经理变更|
因此,预期输出将是:预期产出
| 分配ID|生效开始日期|有效结束日期|行动原因|
| --------------|--------------|--------------|--------------|
| 一千零一|2010年1月1日|2015年2月2日|名称变更|
| 一千零一|2015年3月2日|2021年5月5日|部门变更|
| 一千零一|2021年5月6日|12/31/4712|经理变更|
CREATE TABLE PROD_TABLE(Assignment_ID number, Effective_START_Date date, Effective_END_Date date, ACTION_REASON VARCHAR2(100));
INSERT INTO PROD_TABLE VALUES (30001, TO_DATE('1/1/2010', 'MM/DD/YYYY'), TO_DATE('2/2/2015', 'MM/DD/YYYY'), 'Name Change');
INSERT INTO PROD_TABLE VALUES (30001, TO_DATE('2/3/2015', 'MM/DD/YYYY'), TO_DATE('5/5/2021', 'MM/DD/YYYY'), 'Name Change');
INSERT INTO PROD_TABLE VALUES (30001, TO_DATE('5/6/2021', 'MM/DD/YYYY'), TO_DATE('3/3/2023', 'MM/DD/YYYY'), 'Name Change');
INSERT INTO PROD_TABLE VALUES (30001, TO_DATE('3/4/2023', 'MM/DD/YYYY'), TO_DATE('12/31/4712', 'MM/DD/YYYY'), 'Name Change');
CREATE TABLE STAGING_TABLE(Assignment_ID number, Effective_START_Date date, Effective_END_Date date, ACTION_REASON VARCHAR2(100));
INSERT INTO STAGING_TABLE VALUES (30001, TO_DATE('5/6/2021', 'MM/DD/YYYY'), TO_DATE('12/31/4712', 'MM/DD/YYYY'), 'Manager Change');
现在我有这个SQL无法拉取正确的结果:(
WITH query1 AS (
SELECT staging_table.assignment_id,
GREATEST(staging_table.effective_start_date, prod_table.effective_start_date) AS effective_START_date,
LEAST(staging_table.effective_end_date, prod_table.effective_end_date) AS effective_END_date,
staging_table.ACTION_REASON
FROM PROD_TABLE prod_table
JOIN STAGING_TABLE staging_table
ON prod_table.Assignment_ID = staging_table.Assignment_ID
WHERE prod_table.effective_start_date < staging_table.effective_end_date
AND prod_table.effective_end_date > staging_table.effective_start_date
),
query2 AS (
SELECT *
FROM query1
UNION
SELECT prod_table.Assignment_ID,
prod_table.effective_start_date,
prod_table.effective_end_date,
prod_table.ACTION_REASON
FROM STAGING_TABLE prod_table
WHERE NOT EXISTS (SELECT 1
FROM query1 qry
WHERE prod_table.Assignment_ID = qry.Assignment_ID
AND prod_table.effective_start_date BETWEEN qry.effective_start_date AND qry.effective_end_date)
)
SELECT qry.*
FROM query2 qry;
2条答案
按热度按时间y53ybaqx1#
这是我现在唯一想要的场景
对于您显示的具有精确日期匹配的数据,您可以使用外部联接和合并来在存在匹配时使用分段值,并使用distinct来删除重复项,然后为第二个分段值引入重复项:
如果你想更新主表中的数据,那么你可以使用merge,使用基本相同的逻辑,并使用
delete where
子句来删除现在重复的数据:它更新所有匹配的行,但只更新结束日期和原因,而保留原始的开始日期;然后删除那些与暂存开始日期不匹配的匹配行,只留下一行。
fiddle
但是如果你有与现有日期不完全匹配的分期数据,那么它可能会变得更加复杂;如果是这样的话,那么你需要问一个新的问题,清楚地列出你需要处理的所有场景(间隙,重叠,冲突,...)以及你对每一个场景的预期行为。
3npbholx2#
虽然我不太确定你到底想得到什么(条件是什么),但在我看来,这似乎可以用MODEL clause来完成,它允许你像用excel工作表一样管理数据。
下面的代码并没有完成这项工作,但向您展示了一些调节和操作数据的方法:
样本数据:
主SQL:
结果:
它看起来有点复杂,但它是可靠和快速的。如果你能看一下文档-它迟早会派上用场的。