2017-08-01 60 views
0

我無法找到處理歷史數據的最有效的一組語句。可以說我有兩張桌子。一個分段和一個存檔表。每次將數據導入登臺表我想用下面的邏輯將它插入到歸檔表中。低於該如果插入新的相同行,則設置end_date

if circuitId = circuitId and checksum = checksum(*) 
    then do nothing 

if circuitId = circuiId and checksum <> checksum(*) 
    then insert new row and set end_date of old row. 

if rows exists in archive but not in staging 
    then change delete_flag to 1 

到目前爲止,我已經創建處理delete_flag,如果checksum = checksum(*),但我似乎無法弄清楚,如果checksum <> checksum(*)如何整合和對舊行設置END_DATE。

UPDATE ARCHIVE.F1_CIRCUITS n 
     SET 
      n.DELETE_FLAG = 1 
     FROM 
      ARCHIVE.F1_CIRCUITS n 
       LEFT JOIN EXTRACT.F1_CIRCUITS o 
       ON o."circuitId" = n.CIRCUITID 
       WHERE o."circuitId" IS NULL; 

INSERT INTO ARCHIVE.F1_CIRCUITS 
      SELECT ("circuitId","circuitRef","name","location","country","lat","lng","alt","url", CURRENT_TIMESTAMP, NULL, HASH_MD5("circuitId","circuitRef","name","location","country","lat","lng","alt","url"), 'C', 0) FROM EXTRACT.F1_CIRCUITS o 
      WHERE NOT EXISTS (SELECT 1 
           FROM ARCHIVE.F1_CIRCUITS n 
           WHERE o."circuitId" = n.CIRCUITID AND 
           HASH_MD5(o."circuitId",o."circuitRef",o."name",o."location",o."country",o."lat",o."lng",o."alt",o."url") = n.cheetax_checksum 
          ); 

舞臺架構表

CREATE TABLE EXTRACT.F1_CIRCUITS (
    "circuitId" DECIMAL(11,0), 
    "circuitRef" VARCHAR(255) UTF8, 
    "name"  VARCHAR(255) UTF8, 
    "location" VARCHAR(255) UTF8, 
    "country" VARCHAR(255) UTF8, 
    "lat"  DOUBLE PRECISION, 
    "lng"  DOUBLE PRECISION, 
    "alt"  DECIMAL(11,0), 
    "url"  VARCHAR(255) UTF8 
); 

歸檔架構表

CREATE TABLE F1_CIRCUITS (
    ID      DECIMAL(18,0) IDENTITY, 
    CIRCUITID    DECIMAL(11,0), 
    CIRCUITREF    VARCHAR(255) UTF8, 
    NAME     VARCHAR(255) UTF8, 
    LOCATION    VARCHAR(255) UTF8, 
    COUNTRY     VARCHAR(255) UTF8, 
    LAT      DOUBLE PRECISION, 
    LNG      DOUBLE PRECISION, 
    ALT      DECIMAL(11,0), 
    URL      VARCHAR(255) UTF8, 
    START_TIMESTAMP TIMESTAMP, 
    END_TIMESTAMP TIMESTAMP, 
    CHECKSUM  CHAR(32) UTF8, 
    STATUS   CHAR(1) UTF8, 
    DELETE_FLAG  DECIMAL(1,0) 
); 
+0

什麼是EXTRACT表? –

+0

woops提取物是分期。把所有東西都改爲EXTRACT而不是升級 –

回答

0

對於你的情況,我建議使用觸發器,並使汽車的操作。 以下觸發條件會隨時插入一個新行到您的EXTRACT表(條件1/2)或從中刪除(條件3),並且將檢查:

當插入到EXTRACT:

if circuitId = circuitId and checksum = checksum(*) 
    then do nothing 

if circuitId = circuiId and checksum <> checksum(*) 
    then insert new row and set end_date of old row. 

當從EXTRACT正在刪除:

if rows exists in archive but not in staging 
    then change delete_flag to 1 

觸發您的條件:

CREATE OR REPLACE TRIGGER archiver 
     AFTER INSERT OR DELETE 
      ON EXTRACT.F1_Circuits 
     REFERENCES OLD AS OLD NEW AS NEW 
      FOR EACH ROW 


    DECLARE 

      v_extr_new_row VARCHAR2 (500); --- for storing new inserting row data 
      v_extr_row_checksum RAW(500); --- for storing new row as RAW 
      v_encrypted_raw RAW(2048);  --- encrypted to md5 data 
      v_arch_cir_id NUMBER (11) := 0; --- circuitId from ARCHIVE table 
      v_arch_checksum VARCHAR2 (32) := '0'; --- checksum from ARCHIVE table 
      v_arch_last_chsum NUMBER (3); --- for finding the latest data by checksum in ARCH table 
      v_arch_start_date TIMESTAMP; --- for finding the latest data by start_date in ARCH table 

     BEGIN 

     IF INSERTING THEN 
       --- taking the inserting data into the variable for further converting to md5 
       v_extr_new_row := :NEW."circuitId" || ',' || :NEW."circuitRef" || ',' || :NEW."name" || ',' || 
           :NEW."location" || ',' || :NEW."country" || ',' || :NEW."lat" || ',' || 
           :NEW."lng" || ',' || :NEW."alt" || ',' || :NEW."url"; 

       --- converting the inserting data to hash_md5, checksum 
       v_extr_row_checksum := utl_raw.cast_to_raw(v_extr_new_row); 
       v_encrypted_raw := dbms_crypto.hash(v_extr_row_checksum, 2); 

       --- taking the latest row from the ARCH table for changing the Updating the END_DATE; 
       SELECT START_TIMESTAMP, r_last_chsum, CHECKSUM, circuitId 
         INTO v_arch_start_date, v_arch_last_chsum, v_arch_checksum, v_arch_cir_id 
         FROM 
          (SELECT START_TIMESTAMP, ROW_NUMBER() 
           OVER (PARTITION BY arch_in.circuitId ORDER BY arch_in.START_TIMESTAMP DESC) r_last_chsum, 
           CIRCUITID, CHECKSUM 
           FROM ARCHIVE.F1_CIRCUITS arch_in 
           WHERE arch_in.circuitId = :NEW."circuitId") 
          WHERE r_last_chsum = 1; 


      ---- checking whether the data already exist in the ARCH table 
      IF (v_arch_cir_id = :NEW."circuitId" AND v_arch_checksum <> v_encrypted_raw) 
       THEN 

        ---- Update end_date for old row 
       UPDATE ARCHIVE.F1_CIRCUITS arch 
         SET arch.END_TIMESTAMP = CURRENT_TIMESTAMP 
          WHERE arch.circuitId = :NEW."circuitId" 
            AND arch.CHECKSUM = v_arch_checksum 
            AND arch.START_TIMESTAMP = v_arch_start_date; 

       --- inserting the new data into ARCH table 
       INSERT INTO ARCHIVE.F1_CIRCUITS 
         (CIRCUITID, CIRCUITREF, NAME, LOCATION, COUNTRY, LAT, LNG, ALT, URL, START_TIMESTAMP, END_TIMESTAMP, CHECKSUM, 
          STATUS, DELETE_FLAG) 
         VALUES (:NEW."circuitId", :NEW."circuitRef", :NEW."name", :NEW."location", :NEW."country", 
           :NEW."lat", :NEW."lng", :NEW."alt", :NEW."url", CURRENT_TIMESTAMP, NULL, v_encrypted_raw, 'C', to_number (0)); 

       ---- else if they are EQUAL then DO NOTHING, but if you need you can do;) 
      ELSIF (v_arch_cir_id = :NEW."circuitId" AND v_arch_checksum = v_encrypted_raw) 
        THEN 
        dbms_output.put_line ('Do Nothing!'); 
    /*     INSERT INTO ikrom.f1_circuits_arch ---- ARCHIVE.F1_CIRCUITS 
         (CIRCUITID, CIRCUITREF, NAME, LOCATION, COUNTRY, LAT, LNG, ALT, URL, START_TIMESTAMP, END_TIMESTAMP, CHECKSUM, 
          STATUS, DELETE_FLAG) 
         VALUES (:NEW."circuitId", :NEW."circuitRef", :NEW."name", :NEW."location", :NEW."country", 
           :NEW."lat", :NEW."lng", :NEW."alt", :NEW."url", CURRENT_TIMESTAMP, NULL, v_encrypted_raw, 'C', to_number (0));*/ 
      END IF; 

     END IF; 

     IF DELETING THEN 
        --- taking the inserting data into the variable for further converting to md5 
       v_extr_new_row := :OLD."circuitId" || ',' || :OLD."circuitRef" || ',' || :OLD."name" || ',' || 
           :OLD."location" || ',' || :OLD."country" || ',' || :OLD."lat" || ',' || 
           :OLD."lng" || ',' || :OLD."alt" || ',' || :OLD."url"; 

       --- converting the inserting data to hash_md5, checksum 
       v_extr_row_checksum := utl_raw.cast_to_raw(v_extr_new_row); 
       v_encrypted_raw := dbms_crypto.hash(v_extr_row_checksum, 2); 

       --- taking the latest row from the ARCH table for changing the Updating the END_DATE; 
       SELECT START_TIMESTAMP, r_last_chsum, CHECKSUM, circuitId 
         INTO v_arch_start_date, v_arch_last_chsum, v_arch_checksum, v_arch_cir_id 
         FROM 
          (SELECT START_TIMESTAMP, ROW_NUMBER() 
           OVER (PARTITION BY arch_in.circuitId ORDER BY arch_in.START_TIMESTAMP DESC) r_last_chsum, 
           CIRCUITID, CHECKSUM 
           FROM ARCHIVE.F1_CIRCUITS arch_in 
           WHERE arch_in.circuitId = :OLD."circuitId") 
          WHERE r_last_chsum = 1; 


      ---- checking whether the data already exist in the ARCH table 
      IF (v_arch_cir_id = :OLD."circuitId") 
       THEN 

        ---- Update end_date for old row 
       UPDATE ARCHIVE.F1_CIRCUITS arch 
         SET arch.DELETE_FLAG = 1 
          WHERE arch.circuitId = :OLD."circuitId" 
            AND arch.DELETE_FLAG = 0; 
       END IF;     
      END IF; 

      EXCEPTION 
      WHEN NO_DATA_FOUND 
       THEN 
       ---- if no data found in ARCH table by SELECTING in INSERTING process then just INSERT the new row 
       INSERT INTO ARCHIVE.F1_CIRCUITS 
          (CIRCUITID, CIRCUITREF, NAME, LOCATION, COUNTRY, LAT, LNG, ALT, URL, START_TIMESTAMP, END_TIMESTAMP, CHECKSUM, 
           STATUS, DELETE_FLAG) 
          VALUES (:NEW."circuitId", :NEW."circuitRef", :NEW."name", :NEW."location", :NEW."country", 
            :NEW."lat", :NEW."lng", :NEW."alt", :NEW."url", CURRENT_TIMESTAMP, NULL, v_encrypted_raw, 'C', to_number (0)); 

    END; 

重要說明:從Extract表中刪除時,ARCHIVE中具有相同circuitId的所有行都將被更新; 也爲dbms_crypto授予觸發器運行用戶的執行權限;

+0

@Peter Pik請同時投票回答。謝謝 ;) – Ikrom

0

好像每個circuitid,你想END_DATE/end_timestamp對於最近插入的行始終爲空。爲什麼不直接這樣做,併爲所有不是最近插入的行設置結束時間戳?

update ARCHIVE.F1_CIRCUITS set end_timestamp = current_timestamp 
    where end_timestamp is null 
    and exists (select 1 from ARCHIVE.F1_CIRCUITS n 
     where n.circuitid = f1_circuits.circuitid 
     and n.start_timestamp > f1_circuits.start_timestamp); 

在不同的音符,當我聽到「每次發生事情到這個表的時候,我想要做的事對另一個表」,我首先想到的是使用觸發器。如果您最終在觸發器(或另一個PL/SQL塊)中執行此操作,那麼如果您將校驗和分配給像這樣的變量,那麼這也很容易:new_checksum;你可以這樣做:

update ARCHIVE.F1_CIRCUITS set end_timestamp = current_timestamp 
    where end_timestamp is null and circuitid = :new.circuitid and checksum <> :new_checksum; 
相關問題