概述
我會給四種解決方案,從最簡單的。每個解決方案我都會解釋它適用的情況。
這些解決方案中的每一個假設數據庫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