У меня есть основная схема дб, включающая 2 таблицы; Каждый - простой идентификатор->, текстовый список терминов и другой имеют 2 столбца, родитель и ребенок. Идентификаторы в первой таблице сгенерированы на вставке последовательностью дб, в то время как вторая таблица содержит отображение между ключами для хранения 'структуры' иерархии.
Моя проблема состоит в том, что я могу хотеть иногда переместить дерево от одного дб до другого. Если у меня есть 2 DBS, каждый с 10 условиями в (Условия A базы данных! = Условия B базы данных, и нет никакого перекрытия), и я просто копирую данные от до B затем, я получу очевидную проблему, что условия будут перенумерованы, но привычка отношений. Очевидно в этом примере, просто добавляющем 10 ко всем ключам отношений, будет работать, но кто-либо знает об общем алгоритме, чтобы сделать это?
DB является оракулом 11 г и оракулом, определенное решение прекрасно...
Обзор
Я дам четыре решения, начиная с самой простых. С каждым решением я объясню ситуации, в которых это будет применимо.
Каждое из этих решений предполагает, что базы данных 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 в 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, и менее эффективна, чем некоторые другие решения. Следует использоваться, если:
, следующее будет объединять все термины и отношения из 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
Раньше я занимался этим видом, но моя память немного тумана. Я дам вам общую идею, надеюсь, что она сможет указывать в правильном направлении.
В основном вы можете сделать это только, если у вас есть надежный второй «уникальный ключ» столбца в «родительской» таблице. Если нет, вам нужно создать один.
Скажем, у нас есть эти таблицы
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
Я предполагаю, что эти две базы данных «достаточно подключены», чтобы вы могли сделать запросы с перекрестными базами данных. Если вам нужно сериал в файл, он становится немного больше ... сложно.
Быстрый ответ
Импортируйте в постановку, но заполните сопоставленные значения 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
Способленные значения края могут быть заполнены обратно в постановку таблиц, используя запрос обновления с аналогичным Присоединяйтесь или вставляйте непосредственно в таблицу назначения из запроса, аналогичного выше.
Достаточно ли хорош встроенный тестовый пакет для установки какао? Крис Хэнсон (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;
А как насчет передачи данных в виде XML? Она, естественно, предназначена для работы с древовидными структурами, и многие СУБД имеют хорошую поддержку разбора и преобразования XML.
Для этого необходимо обеспечить отображение узла X в DB1 к узлу Y в DB 2, но для этого следует использовать некоторый факт об узле (имя и т.д.), выходящий за рамки первичного ключа.
Можно также сместить клавиши для каждой БД на регулярную величину (скажем, 2^32) и использовать клавишу BIG INTEGER. Ограничивает количество записей до 2^32, но все же полезно.
(Возможно, я неправильно понял вопрос, но надеюсь, что нет)
.