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.

中的日间数据
  1. 如果今天的数据中有一行但昨天(前一天)的数据中没有,则将 FLAG 更新为 'INSERT'
  2. 如果某行存在于昨天的数据中但不存在于今天的数据中,则将 FLAG 更新为 'DELETE'
  3. 如果一行在今天和昨天的数据中都存在并且这两个记录的 COL3 和 COL4 都有任何变化,请将 FLAG 更新为 'UPDATE'。
  4. 如果今天和昨天的数据中都存在一行并且这两个记录的 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;

db<>fiddle demo

我假设你的 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 是演示。