2017-03-06 1 views
1

ich derzeit Daten aus Legacy-System migrieren bin auf das aktuelle System.Legen Sie in Select-Anweisung auf derselben Tabelle

Ich habe diese INSERT Anweisung innerhalb einer gespeicherten Prozedur.

INSERT INTO TABLE_1 
(PRIMARY_ID, SEQUENCE_ID, DESCR) 
SELECT LEGACY_ID PRIMARY_ID 
, (SELECT COUNT(*) + 1 
    FROM TABLE_1 T1 
    WHERE T1.PRIMARY_ID = L1.LEGACY_ID) SEQUENCE_ID 
, L1.DESCR 
FROM LEGACY_TABLE L1; 

Jedes Mal, wenn ich mehrere Werte von LEGACY_ID von LEGACY_TABLE haben, die Abfrage für die SEQUENCE_ID nicht erhöhen nicht.

Warum ist das so? Ich kann anscheinend keine Dokumentation darüber finden, wie die INSERT INTO SELECT-Anweisung hinter den Kulissen funktioniert. Ich nehme an, dass es alle Werte aus der Tabelle auswählt, die Sie auswählen, und fügt sie dann gleichzeitig ein, deshalb erhöht es den COUNT(*) Wert nicht?

Welche anderen Abhilfen kann ich tun? Ich kann keine SEQUENCE erstellen, da die SEQUENCE_ID auf der Anzahl der vorhandenen PRIMARY_ID basieren muss. Sie sind beide primäre IDs.

Vielen Dank im Voraus.

Antwort

2

Ja, die SELECT wird ausgeführt FIRST und nur dann die INSERT geschieht.

A Simple PL/SQL-Block unten, wird ein einfacher Ansatz, nicht effizient though.

DECLARE 
    V_SEQUENCE_ID NUMBER; 
    V_COMMIT_LIMIT:= 20000; 
    V_ITEM_COUNT := 0; 
BEGIN 
    FOR REC IN (SELECT LEGACY_ID,DESCR FROM LEGACY_TABLE) 
    LOOP 
     V_SEQUENCE_ID:= 0; 

     SELECT COUNT(*)+1 INTO V_SEQUENCE_ID FROM TABLE_1 T1 
     WHERE T1.PRIMARY_ID = REC.LEGACY_ID 


     INSERT INTO TABLE_1 
     (PRIMARY_ID, SEQUENCE_ID, DESCR) 
     VALUES 
     (REC.LEGACY_ID,V_SEQUENCE_ID,REC.DESCR); 

     V_ITEM_COUNT := V_ITEM_COUNT + 1; 

     IF(V_ITEM_COUNT >= V_COMMIT_LIMIT) 
     THEN 
      COMMIT; 
      V_ITEM_COUNT := 0; 
     END IF; 

    END LOOP; 
    COMMIT; 
END; 
/

EDIT: Mit CTE:

WITH TABLE_1_PRIM_CT(PRIMARY_ID, SEQUENCE_ID) AS 
(
    SELECT L1.LEGACY_ID,COUNT(*) 
    FROM LEGACY_TABLE L1 
     LEFT OUTER JOIN TABLE_1 T1 
     ON(L1.LEGACY_ID = T1.PRIMARY_ID) 
    GROUP BY L1.LEGACY_ID 
) 
INSERT INTO TABLE_1 
(SELECT L1.LEGACY_ID, 
     CTE.SEQUENCE_ID+ (ROW_NUMBER() OVER (PARTITION BY L1.LEGACY_ID ORDER BY null)), 
     L1.DESCR 
FROM TABLE_1_PRIM_CT CTE, LEGACY_TABLE L1 
WHERE L1.LEGACY_ID = CTE.PRIMARY_ID); 

PS: Mit Ihren Millionen von Zeilen, das wird eine temporäre Tabelle von gleicher Größe erstellen, die während der Ausführung . Tun Sie Explain Plan vor der tatsächlichen Ausführung.

+0

Gibt es keine andere Möglichkeit? Ich muss das Einfügen in die Tabelle optimieren, da ich mehr als 50 Millionen Datensätze einfügen muss. –

+0

Dies ist kein "schlechter" Weg. Aber einfach für dich zu pflegen. Wir können 'COMMIT' in Chargen einführen. Wenn Sie einen Index für 'PRIMARY ID' von' TABLE1' haben, wird dieser Block mit minimalen Ressourcen gut funktionieren. –

+0

Ich habe Indizes für 'TABLE1'' PRIMARY ID'. Für diese Tabelle sind die Primärschlüssel jedoch "PRIMARY_ID" und "SEQUENCE_ID". Außerdem muss ich andere Felder in 'LEGACY_TABLE' in andere Tabellen wie' TABLE2' und 'TABLE3' einfügen. –

Verwandte Themen