У меня есть две таблицы с полями иерархии, одна из которых представляет собой промежуточную таблицу с новыми данными, которые необходимо объединить с другой (то есть набор узлов, которые необходимо добавить в основное дерево, некоторые из которых уже могут быть там).
В дополнение к столбцу иерархии, который определяет древовидную структуру (отношения родитель/потомок). каждая таблица имеет отдельный столбец, содержащий идентификатор узла, который однозначно идентифицирует каждый узел. То есть способ узнать, находится ли узел из промежуточной таблицы уже в основной таблице, — через идентификатор узла, а не через столбцы иерархии.
В обязательном порядке обработка, которую необходимо выполнить, будет выглядеть примерно так:
For each row, RS, in the staging table:
If there is not already a row with the same Id as RS in the main table:
Find the parent, PS, of the staging row
Find the row, PM, in the main table that has the same node ID as PS
Create a new child, RM of row PM
Set PM's ID equal to the ID of RS
Важно отметить, что этот подход будет работать только в том случае, если дерево в промежуточной таблице сортируется/просматривается в порядке ширины — это делается для того, чтобы при встрече RS было гарантировано, что его родительский PS уже имеет соответствующую строку в основной таблице.
Пока единственный способ добиться этого на SQL-сервере — использовать курсор над промежуточной таблицей (которая уже отсортирована) и вызывать хранимую процедуру для каждой строки, которая, по сути, делает именно то, что описано выше, в комплекте с SELECT. MAX(), чтобы найти наивысший идентификатор иерархии, который уже существует как дочерний элемент PM, чтобы дочерний элемент можно было добавить уникальным образом.
Однако это ужасно неэффективный подход и слишком медленный для моих целей. Есть ли лучший способ?
Для фона, это своего рода проверка осуществимости, которую я делаю. Мне нужно выяснить, могу ли я быстро выполнить эту операцию внутри SQL Server. Если окажется, что я не могу, мне придется сделать это другим способом, вне базы данных. Слияние деревьев присуще (на самом деле, в каком-то смысле является) проблемной области, поэтому структурировать данные по-другому или смотреть на них шире и пытаться каким-то образом вообще избежать выполнения этой операции не рекомендуется. опция.
Обновить
Как и просили, вот конкретный пример.
Таблицы «staging» и «main» имеют одни и те же два столбца:
hierarchy_id of type hierarchyid
node_id of type bigint
Исходное содержание
основной:
hierarchy_id node_id
/1/ 1
/1/1/ 2
/1/2/ 3
/1/3/ 4
постановка:
hierarchy_id node_id
/1/ 1
/1/1/ 3
/1/2/ 5
/1/1/1/ 6
Желаемый контент
основной:
hierarchy_id node_id
/1/ 1
/1/1/ 2
/1/2/ 3
/1/3/ 4
/1/4/ 5
/1/2/1/ 6
Обратите внимание, что узел в промежуточной таблице с иерархией_id /1/1/ соответствует узлу с hiearchy_id /1/2/ в целевой таблице (вот почему node_id важен — нельзя просто копировать значения иерархии_ид). Также обратите внимание, что новый узел с node_id 6 добавляется как дочерний элемент правильного родителя, узла с node_id 3, поэтому иерархия_id важна — она определяет древовидную структуру (отношения родитель/потомок) для любых новых узлов. Любое решение должно учитывать оба аспекта.
MERGE
; вам не разрешено изменять иерархию или у вас будут дубликаты иерархии таким образом? Я построил самоподдерживающийся гибрид списка иерархии/смежности, который может быть тем, что вы ищете, но это немного сложно сказать по вопросу. - person Aaronaught   schedule 14.08.2011