因此,您有复合键和可能的隐式关系,您想用适当的主键列和外键替换它们。
解决这个问题的方法有五个简单的部分:
- 将新列添加到表中。
- 填充主键列。
- 填充外键列。
- 添加约束。
- 删除枚举列。
我将使用 Oracle 语法来解决这个问题,但同样的原则也适用于 SQL Server。
SQL> select * from grandparent
2 /
TE G_COUNTER GF
-- ---------- --
t1 1 ga
t2 1 gb
t2 2 gc
t3 1 gd
SQL> select * from parent
2 /
TE G_COUNTER P_COUNTER PF
-- ---------- ---------- --
t1 1 1 pa
t1 1 2 pb
t1 1 3 pc
t2 1 1 pd
t3 1 1 pe
SQL> select * from child
2 /
TE G_COUNTER P_COUNTER C_COUNTER CF
-- ---------- ---------- ---------- --
t1 1 1 1 ca
t1 1 1 2 cb
t1 1 1 3 cc
t2 1 1 1 cd
t2 1 1 2 ce
t3 1 1 1 cd
6 rows selected.
SQL>
第 1 步:添加新列
SQL> alter table grandparent
2 add g_id number
3 /
Table altered.
SQL> alter table parent
2 add p_id number
3 add g_id number
4 /
Table altered.
SQL> alter table child
2 add c_id number
3 add p_id number
4 /
Table altered.
SQL>
第 2 步:填充主键
SQL> update grandparent
2 set g_id = rownum
3 /
4 rows updated.
SQL> update parent
2 set p_id = rownum
3 /
5 rows updated.
SQL> update child
2 set c_id = rownum
3 /
6 rows updated.
SQL>
第 3 步:填充外键
SQL> update parent p
2 set g_id = ( select g_id
3 from grandparent g
4 where g.tel = p.tel
5 and g.g_counter = p.g_counter)
6 /
5 rows updated.
SQL> update child c
2 set p_id = ( select p_id
3 from parent p
4 where p.tel = c.tel
5 and p.g_counter = c.g_counter
6 and p.p_counter = c.p_counter)
7 /
6 rows updated.
SQL>
第 4 步:添加约束
SQL> alter table grandparent
2 modify g_id not null
3 add constraint g_pk primary key (g_id) using index
4 /
Table altered.
SQL> alter table parent
2 modify p_id not null
3 add constraint p_g_fk foreign key (g_id)
4 references grandparent (g_id)
5 add constraint p_pk primary key (p_id) using index
6 /
Table altered.
SQL> alter table child
2 modify c_id not null
3 add constraint c_p_fk foreign key (p_id)
4 references parent (p_id)
5 add constraint c_pk primary key (c_id) using index
6 /
Table altered.
SQL>
第 5 步:删除否定列
我假设 GRANDPARENT (TEL, G_COUNTER) 代表某种业务密钥。因此,与其放弃它们,我建议您添加一个独特的约束来强制执行规则。 PARENT(G_ID, P_COUNTER) 和 CHILD(G_ID, C_COUNTER) 可能也是如此。你比我更了解你的数据。因此,以下陈述表明您可能想要做的事情;根据您的需要进行调整。
SQL> alter table grandparent
2 add constraint g_uk unique (tel, g_counter) using index
3 /
Table altered.
SQL> alter table parent
2 add constraint p_uk unique (g_id, p_counter) using index
3 /
Table altered.
SQL> alter table parent
2 drop column tel
3 /
Table altered.
SQL> alter table parent
2 drop column g_counter
3 /
Table altered.
SQL> alter table child
2 drop column tel
3 /
Table altered.
SQL> alter table child
2 drop column g_counter
3 /
Table altered.
SQL> alter table child
2 drop column p_counter
3 /
Table altered.
SQL> alter table child
2 add constraint c_uk unique (p_id, c_counter) using index
3 /
Table altered.
SQL>
让我们检查一下表格:
SQL> select * from grandparent
2 /
TE G_COUNTER GF G_ID
-- ---------- -- ----------
t1 1 ga 1
t2 1 gb 2
t2 2 gc 3
t3 1 gd 4
SQL> select * from parent
2 /
P_COUNTER PF P_ID G_ID
---------- -- ---------- ----------
1 pa 1 1
2 pb 2 1
3 pc 3 1
1 pd 4 2
1 pe 5 4
SQL> select * from child
2 /
C_COUNTER CF C_ID P_ID
---------- -- ---------- ----------
1 ca 1 1
2 cb 2 1
3 cc 3 1
1 cd 4 4
2 ce 5 4
1 cd 6 5
6 rows selected.
SQL>
维护主键需要不同风格的 DBMS 中的不同技术。 Oracle 使用序列,SQL Server 使用 AUTO INCREMENT。这是一个单独的问题,已经在 SO 中讨论过了。