2017-03-06 67 views
1

我目前正在將數據從遺留系統遷移到當前系統。插入同一張表上的select語句

我在存儲過程中有這INSERT語句。

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; 

但是,每當我從LEGACY_TABLELEGACY_ID多個值,對於SEQUENCE_ID查詢不遞增。

這是爲什麼呢?我似乎無法找到關於INSERT INTO SELECT聲明如何在幕後工作的任何文檔。我猜測它會選擇你選擇的表中的所有值,然後同時插入它們,這就是爲什麼它不會增加COUNT(*)的值?

我還能做些什麼其他的解決方法?我無法創建SEQUENCE,因爲SEQUENCE_ID必須基於存在的PRIMARY_ID的數量。他們都是主要的ID。

在此先感謝。

回答

2

是的,SELECT將執行FIRST,只有INSERT發生。

下面的一個簡單的PL/SQL塊將是一個更簡單的方法,雖然效率不高。

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; 
/

編輯:使用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:有了您的百萬行,這將創建一個臨時表相同大小的 ,執行過程中。在實際執行之前執行Explain Plan

+0

沒有其他辦法嗎?我需要優化插入表格,因爲我需要插入5000萬條記錄。 –

+0

這不是一個壞的方法。但容易讓你保持。我們可以分批介紹'COMMIT'。如果您有'TABLE1'的'PRIMARY ID'的索引,則此塊將以最少的資源表現良好。 –

+0

我的索引是'TABLE1''' PRIMARY ID'。雖然,對於這個表,主鍵是'PRIMARY_ID'和'SEQUENCE_ID'。另外,我需要在'LEGACY_TABLE'中將其他字段插入其他表中,如'TABLE2'和'TABLE3'。 –