Oracle - я хочу узнать дельта-изменения в таблице базы данных - PullRequest
0 голосов
/ 31 января 2020

Таблица загружается каждую ночь с некоторыми данными (около 100К строк). Затем мое пакетное задание считывает каждую запись из таблицы и обрабатывает ее. Мое требование состоит в том, чтобы обрабатывать только те записи, которые имеют изменения в указанных столбцах c, поскольку нет смысла обрабатывать новую запись, если она не имеет каких-либо изменений по сравнению со вчерашней записью (и это излишне задерживает всю обработку задания).

Предположим, что ниже структура таблицы

Имя таблицы: STAGING_T

Имена столбцов: PK_1 | COL1 | COL2 | COL3 | COL4 | CREATE_DATE | FLAG

CREATE_DATE - это системная дата при загрузке данных в эту таблицу. Это используется для определения данных за день, загруженных в эту таблицу.

  1. Если строка присутствует в сегодняшних данных, но не во вчерашних (за предыдущий день), обновите FLAG до 'INSERT'
  2. Если строка присутствует во вчерашних данных, но не в сегодняшних, обновите FLAG на «DELETE»
  3. Если строка присутствует как в сегодняшних, так и во вчерашних данных и есть какие-либо изменения в COL3 и COL4 обеих записей , обновите FLAG до 'ОБНОВЛЕНИЕ'.
  4. Если в сегодняшних и вчерашних данных есть строка и в COL3 и COL4 обеих записей НЕТ никаких изменений , измените ФЛАГ на «НЕТ ИЗМЕНЕНИЯ».

Общие столбцы, по которым я идентифицирую одни и те же записи вчера и сегодня: 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  

Любые помощь или предложения будут отличными. Спасибо.

Ответы [ 3 ]

0 голосов
/ 31 января 2020

Может быть что-то вроде этого (не проверено):

   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
   )

)
0 голосов
/ 31 января 2020

Вы можете сначала сгенерировать нужные значения, а затем использовать оператор слияния. Вы можете попробовать ниже -

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;

Здесь - демоверсия.

0 голосов
/ 31 января 2020

Вы можете использовать оператор 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

I Я предполагаю, что ваша CREATE_DATE - это дата со временем начала дня. Если нет, используйте TRUNC(CREATE_DATE) вместо CREATE_DATE в запросе.

Cheers !!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...