我有一个包含2个表的基本数据库模式; 一个是简单的ID - >文本术语列表,另一个是2列,父和子.第一个表中的ID是在db序列插入时生成的,而第二个表包含用于存储层次结构的"结构"的键之间的映射.
我的问题是我可能希望有时将树从一个数据库移动到另一个数据库.如果我有2个DB,每个有10个术语(数据库A的术语!=数据库B的术语,并且没有重叠),我只是将数据从A复制到B然后我会遇到一个明显的问题,即术语将是重新编号,但关系不会.显然在这个例子中,只需在所有关系键上添加10就可以了,但是有人知道这样做的一般算法吗?
DB是oracle 11g,oracle特定的解决方案很好......
快速回答
导入到临时表,但从用于从目标表生成ID值的相同序列中填充映射的ID值.这可以保证避免ID值之间的冲突,因为DBMS引擎支持对序列的并发访问.
使用映射的节点上的ID值(见下文)重新映射边缘的ID值是微不足道的.
更长的答案
您将需要一种机制来映射源中的旧键和目标中的新键之间的值.这样做的方法是创建中间登台表,以保存新旧kays之间的映射.
在Oracle中,自动增量键通常使用您描述的方式完成序列.您需要使用"旧"键的占位符构造临时表,以便您可以执行重新映射.使用与应用程序使用的相同序列来填充实际目标数据库表上的ID值.DBMS允许并发访问序列,并使用相同的序列保证您不会在映射的ID值中发生冲突.
如果你有一个类似的架构:
create table STAGE_NODE (
ID int
,STAGED_ID int
)
/
create table STAGE_EDGE (
FROM_ID int
,TO_ID int
,OLD_FROM_ID int
,OLD_TO_ID int
)
/
Run Code Online (Sandbox Code Playgroud)
这将允许您导入到STAGE_NODE表中,保留导入的键值.插入过程将导入表中的原始ID放入STAGED_ID,并从序列中填充ID.
确保使用与填充目标表中的ID列相同的序列.这可确保您在插入最终目标表时不会发生键冲突. 重复使用相同的序列很重要.
作为一个有用的副作用,这也将允许导入在桌面上进行其他操作时运行; 对单个序列的并发读取很好.如有必要,您可以运行此类导入过程,而无需关闭应用程序.
在登台表中进行此映射后,EDGE表中的ID值很容易通过以下查询进行计算:
select node1.ID as FROM_ID
,node2.ID as TO_ID
from STAGE_EDGE se
join STAGE_NODE node1
on node1.STAGED_ID = se.OLD_FROM_ID
join STAGE_NODE node2
on node2.STAGED_ID = se.OLD_TO_ID
Run Code Online (Sandbox Code Playgroud)
可以使用具有类似连接的UPDATE查询将映射的EDGE值填充回登台表,或者从类似于上述查询的查询中直接插入到目标表中.
概述
我将给出四种解决方案,从最简单的开始。对于每个解决方案,我将解释其适用的情况。
这些解决方案均假设数据库 A 和 B 具有下表:
create table Terms
(
ID int identity(1,1),
Text nvarchar(MAX)
)
create table Relationships
(
ParentID int,
ChildID int
)
Run Code Online (Sandbox Code Playgroud)
解决方案1
这是最简单的解决方案。如果出现以下情况,则应使用它:
以下将把 A 中的所有术语和关系合并到 B 中:
insert into A.Terms (Text)
select Text
from A.Terms
where Text not in (select Text from B.Terms)
insert into B.Relationships (ParentID, ChildID)
select
(select ID
from B.Terms BTerms inner join A.Terms ATerms on BTerms.Text = ATerms.Text
where ATerms.ID = Relationships.ParentID),
(select ID
from B.Terms BTerms inner join A.Terms ATerms on BTerms.Text = ATerms.Text
where ATerms.ID = Relationships.ChildID)
from A.Relationships
Run Code Online (Sandbox Code Playgroud)
基本上,您首先复制术语,然后根据文本复制将旧 ID 映射到新 ID 的关系。
注意:在您的问题中,您指出两个输入数据库之间的术语是不相交的。在这种情况下,where第一个子句insert into可以省略。
解决方案2
这是下一个最简单的解决方案。如果出现以下情况,则应使用它:
首先向您的术语表添加一个名为“OldID”的 int 列,然后使用以下命令合并从 A 到 B 的所有术语和关系:
insert into A.Terms (Text, OldID)
select Text, ID
from A.Terms
where Text not in (select Text from B.Terms)
insert into B.Relationships (ParentID, ChildID)
select
(select ID from B.Terms where OldID = ParentID),
(select ID from B.Terms where OldID = ChildID)
from A.Relationships
Run Code Online (Sandbox Code Playgroud)
解决方案3
该解决方案使用迭代。如果出现以下情况,则应使用它:
以下将把 A 中的所有术语和关系合并到 B 中:
declare TermsCursor sys_refcursor;
begin
-- Create temporary mapping table
create table #Temporary (OldID int, NewID int)
-- Add terms one at a time, remembering the id mapping
open TermsCursor for select * from A.Terms;
for term in TermsCursor
loop
insert into B.Terms (Text) values ( term.Text ) returning ID into NewID;
insert into Temporary ( OldID, NewID ) values ( term.ID, NewID );
end loop;
-- Transfer the relationships
insert into B.Relationships (ParentID, ChildID)
select
(select ID
from B.Terms BTerms inner join Temporary on BTerms.ID = Temporary.NewID
where Temporary.OldID = Relationships.ParentID),
(select ID
from B.Terms BTerms inner join Temporary on BTerms.ID = Temporary.NewID
where Temporary.OldID = Relationships.ChildID),
from A.Relationships
-- Drop the temporary table
drop table #Temporary
end
Run Code Online (Sandbox Code Playgroud)
解决方案4
该解决方案是特定于 Oracle 的,要求您知道用于生成 ID 值的序列,并且效率低于其他一些解决方案。如果出现以下情况,则应使用它:
以下将把 A 中的所有术语和关系合并到 B 中:
-- Create temporary mapping table
create table #Temporary (OldID int, NewID int)
-- Add terms to temporary mapping table
insert into #Tempoarary ( OldID, NewID )
select ID, sequence.nexval
from A.Terms
-- Transfer the terms
insert into B.Terms ( ID, Text )
select NewID, Text
from A.Terms inner join Temporary on ID = OldID
-- Transfer the relationships
insert into B.Relationships (ParentID, ChildID)
select
(select ID
from B.Terms BTerms inner join Temporary on BTerms.ID = Temporary.NewID
where Temporary.OldID = Relationships.ParentID),
(select ID
from B.Terms BTerms inner join Temporary on BTerms.ID = Temporary.NewID
where Temporary.OldID = Relationships.ChildID),
from A.Relationships
-- Drop the temporary table
drop table #Temporary
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
718 次 |
| 最近记录: |