Как обновить родительские узлы в новой ветви таблицы списка смежности с помощью SQL Server 2016/17?

У меня есть таблица списка смежности, где мне нужно клонировать набор узлов и вставить его в новую ветку. В основном я хочу клонировать набор узлов, имеющих одинаковую структуру родительских узлов в новой ветке. Я использую временную таблицу, в которой у меня есть исходные и вставленные узлы. Я попытался присоединиться к временной таблице по элементам и использовать CTE, но получил неверный результат.

Я проверил этот ответ, но он не работает, если родительские узлы одинаковы для более чем 1 элемента.

Как правильно обновить родительские узлы (за исключением корневого узла)?

Есть ли способ обновить его без использования временной таблицы?

Стол

|node|parent|item|  
| 1  | Null | a  |  
| 2  | 1    | b  |    
| 3  | 1    | c  |   

Клонированные узлы

|node|parent|item|  
| 4  | Null | a  |  
| 5  | 1    | b  |    
| 6  | 1    | c  |   

Временная таблица

|inserted_node|old_node|item|old_parent|  
| 4           | 1      | a  | Null     |  
| 5           | 2      | b  | 1        |  
| 6           | 3      | c  | 1        |  

Ожидаемый результат

|node|parent|item|  
| 1  | Null | a  |  
| 2  | 1    | b  |    
| 3  | 1    | c  |    
| 4  | Null | a  |  
| 5  | 4    | b  |    
| 6  | 4    | c  |    

Неверный результат

|node|parent|item|  
| 1  | Null | a  |  
| 2  | 1    | b  |    
| 3  | 1    | c  |  
| 4  | Null | a  |  
| 5  | 5    | b  |    
| 6  | 6    | c  |  

SQL-запрос

;WITH CTE AS 
(
SELECT
t.parent AS old_parent,
t2.node AS new_parent
FROM Table t
LEFT JOIN @TempTable t2 ON t2.item = t.item
WHERE t.node IN (SELECT node FROM @TempTable ) AND t.parent IS NOT NULL
)
UPDATE CTE 
SET old_parent = new_parent

person Dmitry Kazakov    schedule 18.03.2018    source источник
comment
Какова логика столбца узла, является ли он идентификатором или жестко запрограммирован? Я предполагаю, что мой вопрос заключается в том, откуда вы знаете, что новые клонированные узлы должны начинаться с номера узла 4?   -  person Niels Berglund    schedule 18.03.2018
comment
@Niels Berglund Да, столбец узла является идентификатором. Я использовал «ВЫВОД Insert.id INTO TempTable». Согласно логике моего приложения, мне нужно вставить новую ветку и только потом обновить ее родительские узлы в новой ветке. Я мог бы решить эту проблему, присоединившись к временной таблице во второй раз. Это правильно?   -  person Dmitry Kazakov    schedule 18.03.2018


Ответы (1)


Я мог бы решить эту проблему, присоединившись к временной таблице во второй раз. Есть ли лучшее решение?

;WITH CTE AS 
(
SELECT
t.parent AS old_parent,
t3.node AS new_parent
FROM Table t
LEFT JOIN @TempTable t2 ON t2.item = t.item
LEFT JOIN @TempTable t3 ON t2.parent = t3.old_node
WHERE t.node IN (SELECT node FROM @TempTable ) AND t2.parent IS NOT NULL
)
UPDATE CTE 
SET old_parent = new_parent
person Dmitry Kazakov    schedule 18.03.2018
comment
Это работает только в том случае, если вам гарантировано, что дочерние узлы всегда являются дочерними элементами родительского (корневого) узла. Я имею в виду, что если узел 3 является дочерним по отношению к узлу 2, то это не сработает. - person Niels Berglund; 18.03.2018
comment
Что, если узел 3 может быть потомком узла 2? Будет ли Level(Depth) полезен в этом случае? Что бы вы предложили для ее решения? - person Dmitry Kazakov; 18.03.2018
comment
Да, уровень может быть полезен. Я бы посоветовал не использовать узел в качестве идентификатора в вашей таблице, это облегчит решение проблемы. Я работаю над некоторым кодом здесь, но сейчас у меня нет времени закончить. - person Niels Berglund; 18.03.2018