Oracle - 我想找出数据库表中的增量变化
Posted
技术标签:
【中文标题】Oracle - 我想找出数据库表中的增量变化【英文标题】:Oracle - I want to find out delta changes in a database table 【发布时间】:2020-01-31 04:04:16 【问题描述】:该表每晚都会加载一些数据(大约 100K 行)。然后我的批处理作业从表中读取每条记录并进行处理。 我的要求是只处理那些在特定列中发生变化的记录,因为如果新记录与昨天的记录相比没有任何变化,则处理新记录是没有意义的(并且不必要地延迟了整个作业的处理)。
请假设以下表格结构
表名:
STAGING_T
列名:
PK_1 | COL1 | COL2 | COL3 | COL4 | CREATE_DATE | FLAG
CREATE_DATE 是数据加载到此表时的系统日期。这用于识别加载到此表中的每日数据。
-
如果今天的数据中存在某行,但昨天(前一天)中没有,则将 FLAG 更新为“INSERT”
如果昨天的数据中存在某行但今天的数据中没有,请将 FLAG 更新为“DELETE”
如果今天和昨天的数据中都存在一行并且两条记录的 COL3 和 COL4 有任何变化,请将 FLAG 更新为“UPDATE”。
如果今天和昨天的数据中都存在一行并且两条记录的 COL3 和 COL4 都没有变化,请将 FLAG 更新为“NO CHANGE”。
我识别昨天和今天相同记录的常用列是 COL1 和 COL2。
**Sample Data**
PK_1 COL1 COL2 COL3 COL4 CREATE_DATE FLAG
1 1000 2000 a x 31.01.2019
2 1000 2001 b y 31.01.2019
3 1000 2002 c z 31.01.2019
4 1000 2000 aa x 30.01.2019
5 1000 2001 b y 30.01.2019
6 1000 2003 d z 30.01.2019
**Expected Output**
PK_1 COL1 COL2 COL3 COL4 CREATE_DATE FLAG
1 1000 2000 a x 31.01.2019 UPDATE
2 1000 2001 b y 31.01.2019 NO CHANGE
3 1000 2002 c z 31.01.2019 INSERT
4 1000 2000 aa x 30.01.2019
5 1000 2001 b y 30.01.2019
6 1000 2003 d z 30.01.2019
任何帮助或建议都会很棒。 谢谢。
【问题讨论】:
您识别昨天和今天的相同记录的常用列有哪些?是 col1 和 col2 吗?示例数据和预期输出将帮助我们为您提供帮助。 是的,它是 col1 和 col2。我还将添加示例数据和预期输出。谢谢:) 我在问题中添加了示例数据和预期输出 【参考方案1】:您可以先生成所需的值,然后使用合并语句。你可以试试下面 -
MERGE INTO DATA T
USING (SELECT D.PK_1, D.COL1, D.COL2, D.COL3, CREATE_DATE, D.COL4,
CASE WHEN CREATE_DATE = (SELECT MAX(CREATE_DATE) FROM DATA) THEN
CASE WHEN LAG(COL3 || '`'||COL4) OVER(PARTITION BY COL1,COL2 ORDER BY CREATE_DATE) IS NULL
THEN 'INSERT'
WHEN LAG(COL3 || '`'||COL4) OVER(PARTITION BY COL1,COL2 ORDER BY CREATE_DATE) = COL3 || '`'||COL4
THEN 'NO CHANGE'
ELSE 'UPDATE'
END
END FLAG
FROM DATA D)
S ON (T.PK_1 = S.PK_1)
WHEN MATCHED THEN UPDATE SET T.FLAG = S.FLAG;
Here 是演示。
【讨论】:
【参考方案2】:可能是这样的(未测试):
update STAGING_T set FLAG = 'INSERT' where PK_1 in (
select PK_1 from
STAGING_T T1
where trunc(CREATE_DATE)=trunc(sysdate) --today
and not exists (
select 1 from
STAGING_T T2
where trunc(CREATE_DATE)=trunc(sysdate-1) --yesterday
and T1.COL1 = T2.COL1 and T1.COL2 = T2.COL2 and T1.COL3 = T2.COL3
and T1.COL4 = T2.COL4
)
)
update STAGING_T set FLAG = 'DELETE' where PK_1 in (
select PK_1 from
STAGING_T T1
where trunc(CREATE_DATE)=trunc(sysdate-1) --yesterday
and not exists (
select 1 from
STAGING_T T2
where trunc(CREATE_DATE)=trunc(sysdate) --today
and T1.COL1 = T2.COL1 and T1.COL2 = T2.COL2 and T1.COL3 = T2.COL3
and T1.COL4 = T2.COL4
)
)
update STAGING_T set FLAG = 'update' where PK_1 in (
select PK_1 from
STAGING_T T1
where trunc(CREATE_DATE)=trunc(sysdate-1) --yesterday
and exists (
select 1 from
STAGING_T T2
where trunc(CREATE_DATE)=trunc(sysdate) --today
and T1.COL1 = T2.COL1 and T1.COL2 = T2.COL2 and T1.COL3 <> T2.COL3
and T1.COL4 <> T2.COL4
)
)
update STAGING_T set FLAG = 'no change' where PK_1 in (
select PK_1 from
STAGING_T T1
where trunc(CREATE_DATE)=trunc(sysdate-1) --yesterday
and exists (
select 1 from
STAGING_T T2
where trunc(CREATE_DATE)=trunc(sysdate) --today
and T1.COL1 = T2.COL1 and T1.COL2 = T2.COL2 and T1.COL3 = T2.COL3
and T1.COL4 = T2.COL4
)
)
【讨论】:
【参考方案3】:您可以在源代码部分使用MERGE
语句和aggregate functions
,如下所示:
MERGE INTO DATA T
USING (
SELECT COL1, COL2,
MAX(CASE WHEN TRUNC(SYSDATE) = CREATE_DATE THEN PK_1 END) TODAY_PK,
MAX(CASE WHEN TRUNC(SYSDATE) - 1 = CREATE_DATE THEN PK_1 END) YEST_PK,
COUNT(DISTINCT COL3) AS CNT_COL3,
COUNT(DISTINCT COL4) AS CNT_COL4
FROM DATA T
WHERE CREATE_DATE BETWEEN TRUNC(SYSDATE - 1) AND TRUNC(SYSDATE)
GROUP BY COL1, COL2
)
S ON ( T.COL1 = S.COL1
AND T.COL2 = S.COL2
AND T.CREATE_DATE = TRUNC(SYSDATE) )
WHEN MATCHED THEN UPDATE SET T.FLAG = CASE
WHEN S.YEST_PK IS NULL THEN 'INSERT'
WHEN S.TODAY_PK IS NULL THEN 'DELETE'
WHEN S.CNT_COL3 > 1
OR S.CNT_COL4 > 1 THEN 'UPDATE'
ELSE 'NO CHANGE'
END;
db<>fiddle demo
我假设您的 CREATE_DATE
是一个以时间为开始的日期,如果不是,请在查询中使用 TRUNC(CREATE_DATE)
而不是 CREATE_DATE。
干杯!!
【讨论】:
这没有产生正确的输出 - dbfiddle.uk/… 好的,有个小错误-1应该在MAX
的左边。更新了答案。请立即检查!以上是关于Oracle - 我想找出数据库表中的增量变化的主要内容,如果未能解决你的问题,请参考以下文章
SQOOP增量抽取时,在HIVE中实现类似Oracle的merge操作