假设这是您的非规范化table_x,由三个父-子级别组成,其中key_n是级别n的*原始键和col_n各自的属性。
select * from table_x;
KEY_1 COL_1 KEY_2 COL_2 KEY_3 COL_3
---------- ---------- ---------- ---------- ---------- ----------
100 a 101 aa 101 aaa
100 a 101 aa 102 aab
100 a 102 ab 103 aba
100 a 102 ab 104 abb
200 b 103 ba 105 baa
200 b 103 ba 106 bab
200 b 104 bb 107 bba
200 b 104 bb 108 bbb
使用一些分析函数,您可以确定要在哪个级别插入哪一行并分配新的主键。
这里
.
with norm as (
select
row_number() over (partition by KEY_1 order by KEY_2, KEY_3) lev_1_rn,
KEY_1, COL_1,
row_number() over (partition by KEY_1,KEY_2 order by KEY_3) lev_2_rn,
KEY_2, COL_2,
row_number() over (partition by KEY_1,KEY_2,KEY_3 order by COL_3) lev_3_rn,
KEY_3, COL_3
from table_x)
select
lev_1_rn,
sum(case when lev_1_rn = 1 then 1 end) over (order by KEY_1) id1,
KEY_1, COL_1,
lev_2_rn,
sum(case when lev_2_rn = 1 then 1 end) over (order by KEY_1, KEY_2) id2,
KEY_2, COL_2,
lev_3_rn,
sum(case when lev_3_rn = 1 then 1 end) over (order by KEY_1, KEY_2, KEY_3) id3,
KEY_3, COL_3
from norm;
LEV_1_RN ID1 KEY_1 COL_1 LEV_2_RN ID2 KEY_2 COL_2 LEV_3_RN ID3 KEY_3 COL_3
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
1 1 100 a 1 1 101 aa 1 1 101 aaa
2 1 100 a 2 1 101 aa 1 2 102 aab
3 1 100 a 1 2 102 ab 1 3 103 aba
4 1 100 a 2 2 102 ab 1 4 104 abb
1 2 200 b 1 3 103 ba 1 5 105 baa
2 2 200 b 2 3 103 ba 1 6 106 bab
3 2 200 b 1 4 104 bb 1 7 107 bba
4 2 200 b 2 4 104 bb 1 8 108 bbb
剩下的就是INSERT ALL 的任务,使用上面的查询并为每个级别约束相关的行和属性(pk + fk)
insert all
when LEV_1_RN = 1 then
into table_a (id, key_1, col_1) values(ID1, KEY_1, COL_1)
when LEV_2_RN = 1 then
into table_b (id, fk_id, key_2, col_2) values(ID2, ID1, KEY_2, COL_2)
when LEV_3_RN = 1 then
into table_c (id, fk_id, key_3, col_3) values(ID3, ID2, KEY_3, COL_3)
with norm as (
select
row_number() over (partition by KEY_1 order by KEY_2, KEY_3) lev_1_rn,
KEY_1, COL_1,
row_number() over (partition by KEY_1,KEY_2 order by KEY_3) lev_2_rn,
KEY_2, COL_2,
row_number() over (partition by KEY_1,KEY_2,KEY_3 order by COL_3) lev_3_rn,
KEY_3, COL_3
from table_x)
select
lev_1_rn,
sum(case when lev_1_rn = 1 then 1 end) over (order by KEY_1) id1,
KEY_1, COL_1,
lev_2_rn,
sum(case when lev_2_rn = 1 then 1 end) over (order by KEY_1, KEY_2) id2,
KEY_2, COL_2,
lev_3_rn,
sum(case when lev_3_rn = 1 then 1 end) over (order by KEY_1, KEY_2, KEY_3) id3,
KEY_3, COL_3
from norm;
产生这个结果
select * from table_a;
ID KEY_1 COL_1
---------- ---------- ----------
1 100 a
2 200 b
select * from table_b;
ID FK_ID KEY_2 COL_2
---------- ---------- ---------- ----------
1 1 101 aa
2 1 102 ab
3 2 103 ba
4 2 104 bb
select * from table_c;
ID FK_ID KEY_3 COL_3
---------- ---------- ---------- ----------
2 1 102 aab
4 2 104 abb
6 3 106 bab
8 4 108 bbb
我假设这将是(对于大表)最有效的转换(因为您省略了循环和查找)。
如果您维护新表是单用户模式(无多用户),您实际上不需要序列,但如果您愿意,您可以在转换后使用适当的设置初始值部署它们。