概述
我会给四种解决方案,从最简单的。每个解决方案我都会解释它适用的情况。
这些解决方案中的每一个假设数据库A和B具有以下表:
create table Terms
(
ID int identity(1,1),
Text nvarchar(MAX)
)
create table Relationships
(
ParentID int,
ChildID int
)
溶液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
基本上你第一个副本然后根据文本复制将旧ID映射到新ID的关系。
注意:在您的问题中,您声明两个输入数据库之间的术语不相交。在这种情况下,可以省略第一个insert into
中的where
子句。
溶液2
这是下一个最简单的解决方案。它应该被用来当:
首先添加一个int的列到你的条款表所谓“OLDID”,然后用下面从合并的所有条款和关系,以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
解决方案3
此解决方案使用迭代。它应该被用来当:
- 条款具有相同文本必须保持不同,并
- 不能修改目标表,并
- 无论(一)您的ID列是标识列(在Oracle中,这意味着它有一个使用序列触发),或(b)你想将与任何数据库技术工作的一般方法
以下将合并所有的条款和RELAT ionships从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
解决方案4
该溶液是Oracle特定的,需要你知道用于生成ID值的序列,并且是比一些其他的解决方案的效率较低。它应该被用来当:
- 条款具有相同文本必须保持不同,并
- 不能修改目标表,并
- 您可以访问生成的ID列的顺序,并
- 一切都OK使用techinique不会移植到非Oracle数据库技术
以下将合并所有方面和关系从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
不是一个真正的答案,但你有没有考虑用Perl或Python脚本来处理的举动? – Pace 2010-01-29 13:37:06
我担心树结构的SQL真的很像一个圆形的圆孔。只能使用过量的暴力。 – 2010-01-29 13:39:43
不是你的问题的答案,但有一个特定的理由让你的父母/孩子的关系在一个单独的表?如果每个术语只能有一个父项,则术语表可以有一个父项列。当你需要找到孩子时,你可以使用'select-from-connect by-start with'语句。这也会使根节点更加明显,因为它们的父列将为空。 – Aaron 2010-01-29 15:04:55