在同一个 table 上插入 select 语句
Insert into select statement on the same table
我目前正在将数据从遗留系统迁移到当前系统。
我在存储过程中有这个 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_TABLE
的多个 LEGACY_ID
值时,对 SEQUENCE_ID
的查询不会递增。
为什么会这样?我似乎找不到任何关于 INSERT INTO SELECT
语句在幕后如何工作的文档。我猜它会从您选择的 table 中选择所有值,然后同时插入它们,这就是为什么它不会增加 COUNT(*)
值?
我还能采取哪些其他解决方法?我无法创建 SEQUENCE
,因为 SEQUENCE_ID
必须基于存在的 PRIMARY_ID
的数量。它们都是主 ID。
提前致谢。
是的,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;
/
EDIT: Using 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: With your Millions of Rows, this is going to create a temp table
of same size, during execution. Do Explain Plan
before actual execution.
我目前正在将数据从遗留系统迁移到当前系统。
我在存储过程中有这个 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_TABLE
的多个 LEGACY_ID
值时,对 SEQUENCE_ID
的查询不会递增。
为什么会这样?我似乎找不到任何关于 INSERT INTO SELECT
语句在幕后如何工作的文档。我猜它会从您选择的 table 中选择所有值,然后同时插入它们,这就是为什么它不会增加 COUNT(*)
值?
我还能采取哪些其他解决方法?我无法创建 SEQUENCE
,因为 SEQUENCE_ID
必须基于存在的 PRIMARY_ID
的数量。它们都是主 ID。
提前致谢。
是的,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;
/
EDIT: Using 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: With your Millions of Rows, this is going to create a temp table of same size, during execution. Do
Explain Plan
before actual execution.