首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >从数据库导出/导入层次结构图

从数据库导出/导入层次结构图
EN

Stack Overflow用户
提问于 2010-01-26 23:53:43
回答 5查看 765关注 0票数 8

我有一个基本的数据库模式,包括两个表;一个是简单的ID -> Text list of terms,另一个有2列,parent和child。第一个表中的in是在插入时由db序列生成的,而第二个表包含键之间的映射,以存储分层结构的“结构”。

我的问题是,有时我可能想要将树从一个数据库移动到另一个数据库。如果我有两个DB,每个DB都有10个术语(数据库A的术语!=数据库B的术语,没有重叠),而我只是将数据从A复制到B,那么我会得到一个明显的问题,即术语将被重新编号,但关系不会。显然,在这个例子中,只需将10加到所有的关系键上就可以了,但是有谁知道一个通用的算法来做到这一点吗?

数据库是oracle 11g,一个特定于oracle的解决方案就可以了…

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2010-01-30 02:26:51

概述

我将给出四个解决方案,从最简单的开始。对于每个解决方案,我将解释它适用的情况。

这些解决方案中的每一个都假定数据库A和B具有以下表:

代码语言:javascript
运行
复制
create table Terms
(
  ID int identity(1,1),
  Text nvarchar(MAX)
)

create table Relationships
(
  ParentID int,
  ChildID int
)

解决方案1

这是最简单的解决方案。在以下情况下应使用它:

具有相同文本的

  • 术语可以合并到

下面将把所有术语和关系从A合并到B中:

代码语言:javascript
运行
复制
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

这是下一个最简单的解决方案。在以下情况下应使用它:

具有相同文本的

  • 术语必须保持不同,
  • 您可以将列添加到目标表

首先在Terms表中添加一个名为"OldID“的int列,然后使用以下命令将所有术语和关系从A合并到B:

代码语言:javascript
运行
复制
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

此解决方案使用迭代。在以下情况下应使用它:

具有相同文本的

  • 术语必须保持不同,并且
  • 您不能修改目标表,并且
  • (a)您的ID列是标识列(在Oracle中,这意味着它具有使用序列的触发器),或者(b)您需要一种适用于任何数据库技术的通用方法

下面将把所有术语和关系从A合并到B中:

代码语言:javascript
运行
复制
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列的序列,
  • 您可以使用不会移植到非Oracle数据库技术的技术

下面将把所有术语和关系从A合并到B中:

代码语言:javascript
运行
复制
-- 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
票数 3
EN

Stack Overflow用户

发布于 2010-01-29 21:40:41

快速回答

导入到临时表中,但从用于从目标表生成ID值的同一序列填充映射的ID值。这保证避免ID值之间的冲突,因为DBMS引擎支持对序列的并发访问。

映射节点上的ID值后(请参见下文),重新映射边的ID值很简单。

较长的应答

您需要一种在源中的旧键和目标中的新键之间映射值的机制。要做到这一点,方法是创建中间临时表,其中包含新旧kays之间的映射。

在Oracle中,自动增量键通常以您所描述的方式使用序列来完成。您需要使用“旧”键的占位符来构造临时表,以便可以进行重新映射。使用与应用程序相同的顺序填充实际目标数据库表上的ID值。DBMS允许对序列进行并发访问,并且使用相同的序列可以保证在映射的ID值中不会发生冲突。

如果您有这样的架构:

代码语言:javascript
运行
复制
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
)
/

这将允许您导入到STAGE_NODE表中,同时保留导入的键值。插入过程将导入表中的原始ID放入STAGED_ID中,并从序列中填充ID。

确保使用与填充目标表中的ID列相同的顺序。这可以确保在插入到最终目标表时不会发生键冲突。重用相同的sequence.As很重要,这是一个有用的副作用,它还允许在对表执行其他操作的同时运行导入;对单个序列进行并发读取就可以了。如有必要,您可以在不关闭应用程序的情况下运行此类型的导入过程。

一旦在临时表中有了这个映射,就很容易使用如下查询来计算边缘表中的ID值:

代码语言:javascript
运行
复制
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 

映射的边缘值可以使用具有类似联接的UPDATE查询重新填充到临时表中,或者直接从与上面类似的查询中插入到目标表中。

票数 5
EN

Stack Overflow用户

发布于 2010-01-29 22:34:10

我以前经常做这样的事情,但我的记忆力有点模糊。我会给你一个大概的想法,希望它能给你指明正确的方向。

基本上,只有在“parent”表中有一个可靠的第二个“唯一键”列时,才能做到这一点。如果没有,您将需要创建一个。

假设我们有这些表

代码语言:javascript
运行
复制
ITEMS[id, A, key] //id: 'real' id, A: just some column, key: the alternate key

HIERARCHY[idparent, idchild]

您要做的是首先将项目从SOURCEDB复制到TARGETDB,让TARGETDB为id列创建自己的值。

然后,您需要将层次结构从SOURCEDB复制到TARGETDB,但是您需要执行如下连接操作来获得新的id:

代码语言:javascript
运行
复制
SOURCEDB.HIERARCHY.idparent 
      -> SOURCEDB.ITEMS.id 
      -> SOURCEDB.ITEMS.key 
      -> TARGETDB.ITEMS.key 
      -> TARGETDB.ITEMS.id

您还需要对idchild列执行相同的操作。

这将会得到类似这样的结果(未经测试,生疏,可能还有mssql语法):

代码语言:javascript
运行
复制
//step 1
INSERT TARGETDB.ITEMS(A, key)
SELECT A, key FROM SOURCEDB.ITEMS

//step 2
INSERT TARGETDB.HIERARCHY(idparent, idchild)
SELECT T1.id, T2.id
FROM SOURCEDB.HIERARCHY AS H1
     INNER JOIN SOURCEDB.ITEMS AS I1 ON H1.idparent = I1.id
     INNER JOIN TARGETDB.ITEMS AS T1 ON I1.key = T1.key
     INNER JOIN SOURCEDB.ITEMS AS I2 ON H1.idchild = I2.id
     INNER JOIN TARGETDB.ITEMS AS T2 ON I2.key = T2.key

我假设这两个数据库有足够的“连接”,你可以进行跨数据库查询。如果你必须序列化到文件,它会变得更多一点...很复杂。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2140512

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档