Oracle - 我想找出数据库中的增量变化 table
Oracle - I want to find out delta changes in a database table
table 每晚都会加载一些数据(大约 10 万行)。然后我的批处理作业从 table 中读取每条记录并对其进行处理。
我的要求是只处理那些对特定列有更改的记录,因为如果新记录与昨天的记录相比没有任何变化,则处理新记录没有意义(并且不必要地延迟整个作业的处理)。
请假设以下table结构
Table 姓名:
STAGING_T
列名称:
PK_1 | COL1 | COL2 | COL3 | COL4 | CREATE_DATE | FLAG
CREATE_DATE是数据加载到这个table时的sysdate。这用于识别加载到此 table.
中的日间数据
- 如果今天的数据中有一行但昨天(前一天)的数据中没有,则将 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
任何帮助或建议都会很棒。
谢谢。
您可以在源代码部分将 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;
我假设你的 CREATE_DATE
是一个以时间为一天开始的日期,如果不是,请在查询中使用 TRUNC(CREATE_DATE)
而不是 CREATE_DATE。
干杯!!
可能是这样的(未测试):
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
)
)
您可以先生成需要的值,再使用合并语句。您可以尝试以下 -
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 是演示。
table 每晚都会加载一些数据(大约 10 万行)。然后我的批处理作业从 table 中读取每条记录并对其进行处理。 我的要求是只处理那些对特定列有更改的记录,因为如果新记录与昨天的记录相比没有任何变化,则处理新记录没有意义(并且不必要地延迟整个作业的处理)。
请假设以下table结构
Table 姓名:
STAGING_T
列名称:
PK_1 | COL1 | COL2 | COL3 | COL4 | CREATE_DATE | FLAG
CREATE_DATE是数据加载到这个table时的sysdate。这用于识别加载到此 table.
中的日间数据- 如果今天的数据中有一行但昨天(前一天)的数据中没有,则将 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
任何帮助或建议都会很棒。 谢谢。
您可以在源代码部分将 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;
我假设你的 CREATE_DATE
是一个以时间为一天开始的日期,如果不是,请在查询中使用 TRUNC(CREATE_DATE)
而不是 CREATE_DATE。
干杯!!
可能是这样的(未测试):
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
)
)
您可以先生成需要的值,再使用合并语句。您可以尝试以下 -
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 是演示。