Экспорт/Импорт иерархического графика от базы данных

У меня есть основная схема дб, включающая 2 таблицы; Каждый - простой идентификатор->, текстовый список терминов и другой имеют 2 столбца, родитель и ребенок. Идентификаторы в первой таблице сгенерированы на вставке последовательностью дб, в то время как вторая таблица содержит отображение между ключами для хранения 'структуры' иерархии.

Моя проблема состоит в том, что я могу хотеть иногда переместить дерево от одного дб до другого. Если у меня есть 2 DBS, каждый с 10 условиями в (Условия A базы данных! = Условия B базы данных, и нет никакого перекрытия), и я просто копирую данные от до B затем, я получу очевидную проблему, что условия будут перенумерованы, но привычка отношений. Очевидно в этом примере, просто добавляющем 10 ко всем ключам отношений, будет работать, но кто-либо знает об общем алгоритме, чтобы сделать это?

DB является оракулом 11 г и оракулом, определенное решение прекрасно...

8
задан PaulJWilliams 26 January 2010 в 15:53
поделиться

5 ответов

Обзор

Я дам четыре решения, начиная с самой простых. С каждым решением я объясню ситуации, в которых это будет применимо.

Каждое из этих решений предполагает, что базы данных 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 на новый идентификатор на основе текста.

Примечание. В вашем вопросе вы утверждаете, что условия несерьезны между двумя входными базами данных. В этом случае где пункт в первом вставляет в в может быть опущен.

Решение 2

Это следующее простейшее решение. Его следует использовать, если:

  • термины с тем же текстом должны быть удержаны отчетливым, а
  • вы можете добавить столбец к таблице назначения

сначала добавьте столбец INT в таблицу «OldID», затем Используйте следующее, чтобы объединить все термины и отношения от 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

Решение 3

Это решение использует итерацию. Он должен использоваться, если:

  • термины с одним и тем же текстом должны быть отдельными, а
  • вы не можете изменить таблицу назначения, а
  • либо (A) Ваш столбец ID - это идентичность Столбец (в Oracle это означает, что он имеет триггер, который использует последовательность), или (b) (b) (b) (b) Вы хотите общий метод, который будет работать с любой технологией базы данных

, следующее будет объединять все термины и отношения Из 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, а
  • Вы в порядке, используете Techinique, который не будет портировать технологию без Oracle Database

, следующее будет объединять все термины и отношения из 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
3
ответ дан 5 December 2019 в 20:16
поделиться

Раньше я занимался этим видом, но моя память немного тумана. Я дам вам общую идею, надеюсь, что она сможет указывать в правильном направлении.

В основном вы можете сделать это только, если у вас есть надежный второй «уникальный ключ» столбца в «родительской» таблице. Если нет, вам нужно создать один.

Скажем, у нас есть эти таблицы

ITEMS[id, A, key] //id: 'real' id, A: just some column, key: the alternate key

HIERARCHY[idparent, idchild]

, что вы хотите сделать, - это первые элементы копирования из SourcedB в TargetDB, позволяя TargetDB создавать свои собственные значения для столбца ID.

Затем вам нужно скопировать иерархию из SourcedB в TargetDB, но вам нужно сделать соединение, как правило, чтобы получить новый идентификатор:

SOURCEDB.HIERARCHY.idparent 
      -> SOURCEDB.ITEMS.id 
      -> SOURCEDB.ITEMS.key 
      -> TARGETDB.ITEMS.key 
      -> TARGETDB.ITEMS.id

, и вам нужно сделать то же самое для столбца idchild.

Это даст что-то вроде этого (непроверенного и ржавого и, вероятно, MSSQL Syntax):

//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
ответ дан 5 December 2019 в 20:16
поделиться

Быстрый ответ

Импортируйте в постановку, но заполните сопоставленные значения ID с одной и той же последовательности , используемые для получения значений ID из таблицы назначения. Это гарантируется избегать конфликтов между значениями идентификаторов, поскольку двигатель СУБД поддерживает параллельный доступ к последовательностям.

С значениями идентификатора на узле отображаются сопоставленные (см. Ниже), повторное отображение значений идентификатора для краев - тривиаль.

Дольше ответа

Вам понадобится механизм, который отображает значения между старыми ключами из источника и новых ключей в пункте назначения. Способ сделать это - создать промежуточные постановки столов, которые удерживают отображения между старыми и новыми kays.

В Oracle клавиши AutoNectioning обычно делаются с последовательностями в значительной степени, как вы описали. Вам нужно построить столы постановки с заполнителем для «старого» ключа, чтобы вы могли сделать повторное сопоставление. Используйте ту же последовательность, которая используется приложением для заполнения значений идентификатора на фактических таблицах баз данных назначения. СУБД обеспечивает одновременное доступу к последовательностям и использование той же последовательности гарантирует, что вы не получите столкновения в сопоставленных значениях идентификаторов.

Если у вас есть схема, такая как:

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 , сохраняя их значения ключевых элементов. Процесс вставки помещает исходный идентификатор из импортируемой таблицы в STEDED_ID и заполняет идентификатор от последовательности.

Убедитесь, что вы используете одну и ту же последовательность, которая используется для заполнения столбца 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 

Способленные значения края могут быть заполнены обратно в постановку таблиц, используя запрос обновления с аналогичным Присоединяйтесь или вставляйте непосредственно в таблицу назначения из запроса, аналогичного выше.

5
ответ дан 5 December 2019 в 20:16
поделиться

Достаточно ли хорош встроенный тестовый пакет для установки какао? Крис Хэнсон (Chris Hanson) сделал серию постов по тестированию установки в XCode , и есть также документация Apple ..

-121--4378821-

Хранение IP-адресов является хорошей практикой для входа в систему и отслеживания, но я думаю, что просто captcha остановит спам, грубые атаки и наводнения.

Рекаптча действительно является хорошим решением.

-121--2929492-

С помощью временной таблицы в целевой базе данных можно достичь необходимых результатов. Поскольку идентификаторы генерируются автоматически, следующий код не создает конфликтов.

Предполагается, что исходная база данных называется SourceDb, а целевая база данных - TargetDb. Я также собираюсь оценить эту структуру таблицы:
Термины : ID , Текст
Отношения : ParentId , ChildId

Создание временной таблицы в TargetDb со следующей структурой:
TempTerms : OldId , Text , OldParentId , NewId , NewParentId

Следующий код копирует поддерево в целевую базу данных.

declare
    RootOfSubtreeId SourceDb.Terms.Id%type;
    TermCursor sys_refcursor;
begin
    --//Copy the data from SourceDb into the TargetDb temp table.
    --//This query gets the entire subtree of data with the root of the subtree having ID=RootOfSubTreeId.
    insert into TargetDb.TempTerms
    (
        OldId, Text, OldParentId
    )
    with RelatedTerms as
    (
        select
            T.ID, T.Text, R.ParentId
        from
            SourceDb.Terms T
            join SourceDb.Relationships R
            on R.ChildId = T.ID
    )
    select
        ID,
        Text,
        ParentId
    from
        RelatedTerms
    connect by
        prior ID = ParentId
    start with
        ID = RootOfSubtreeId;

    --//Open a cursor to loop over all of the temporary data.
    open TermCursor for
    select
        *
    from
        TargetDb.TempTerms;

    for term in TermCursor
    loop
        --//Insert the item into TargetDb's Terms table and get the new id back.
        insert into TargetDb.Terms
        ( ID, Text )
        values
        ( term.Text )
        returning ID into NewTermId;

        --//Update the temp table's NewId column for the newly inserted row.
        update TargetDb.TempTerms
        set    NewId = NewTermId
        where  OldId = term.OldId;

        --//Update the temp table's NewParentId column for all children of the newly inserted row.
        update TargetDb.TempTerms
        set    NewParentId = NewTermId
        where  OldParentId = term.OldId;
    end loop;

    --//Add all relationship data to TargetDb using the new IDs found above.
    insert into TargetDb.Relationships
    ( ParentId, ChildId )
    select
        NewParentId, NewId
    from
        TargetDb.TempTerms
    where
        NewParentId is not null;
end;
0
ответ дан 5 December 2019 в 20:16
поделиться

А как насчет передачи данных в виде XML? Она, естественно, предназначена для работы с древовидными структурами, и многие СУБД имеют хорошую поддержку разбора и преобразования XML.

Для этого необходимо обеспечить отображение узла X в DB1 к узлу Y в DB 2, но для этого следует использовать некоторый факт об узле (имя и т.д.), выходящий за рамки первичного ключа.

Можно также сместить клавиши для каждой БД на регулярную величину (скажем, 2^32) и использовать клавишу BIG INTEGER. Ограничивает количество записей до 2^32, но все же полезно.

(Возможно, я неправильно понял вопрос, но надеюсь, что нет)

.
0
ответ дан 5 December 2019 в 20:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: