2016-01-17 3 views
1

У меня есть таблица, какЕсть ли лучший способ построить этот запрос?

 CommentPaths 
============================ 
ancestor_id | descendant_id 
============================ 
    1   1 
    1   2 
    1   3 
    1   4 
    1   5 
    1   6 
    1   7 
    2   2 
    2   4 
    2   5 
    4   4 
    5   5 
    3   3 
    3   6 
    3   7 
    6   6 
    7   7 

предназначенный для представления структуры дерева как

 1 
    / \ 
    2  3 
    /\  \ 
    4 5  6 
      /
      7 

Предположим, что я удалить 2. Затем мне нужно удалить записи, указанные ниже.

 CommentPaths 
============================ 
ancestor_id | descendant_id 
============================ 
    1   1 
    1   2 <------------- 
    1   3 
    1   4 
    1   5 
    1   6 
    1   7 
    2   2 <------------- 
    2   4 <------------- 
    2   5 <------------- 
    4   4 <------------- 
    5   5 <------------- 
    3   3 
    3   6 
    3   7 
    6   6 
    7   7 

Другими словами, при удалении k из дерева мне нужно

  1. Удалить все строки, в которых ancestor_id равно k
  2. Удалить все строки, где descendant_id равняется там ancestor_id это один из тех, от 1.

Так что мой запрос будет выглядеть как-то например

SELECT descendant_id FROM CommentPaths WHERE ancestor_id=2 AS descs 
DELETE FROM CommentPaths WHERE ancestor_id IN descs 
DELETE FROM CommentPaths WHERE descendant_id IN descs 

или есть более удобный, более компактный способ сделать это ????

+0

Почему все свое потомство? –

+0

Имеет ли ancestor_id = descendant_id? – openwonk

+0

@KoebmandSTO Вот так оно представлено на стр. 36 этой книги. Я читаю https://pragprog.com/book/bksqla/sql-antipatterns. Я тоже никогда не понимал, почему. – user5648283

ответ

1
-- delete relation from tree 
with tree (commentTreeID, ancestor, descendant , path, src) as 
(
select id, ancestor_id, descendant_id , cast ('-'+ cast(id as varchar(2000)) +'-' as varchar(2000)) , 0from 
CommentPath ct 
where ct.ancestor_id = 2 
union all 
select CT.Id, CT.ancestor_id, CT.descendant_id ,cast(t.path + '-' + cast(id as varchar(2000)) +'-' as varchar(2000)), 1 
from tree t 
join CommentPath CT 
on CT.ancestor_id = t.descendant and 
    CHARINDEX (cast('-' + cast(id as varchar(2000)) +'-' as varchar(2000)), t.path) = 0 and 
    t.src != 2 
union all 
select CT.Id, CT.descendant_id, CT.ancestor_id ,cast(t.path + '-' + cast(id as varchar(2000)) +'-' as varchar(2000)), 2 
from tree t 
join CommentPath CT 
on CT.descendant_id = t.descendant and 
CHARINDEX(cast('-' + cast(id as varchar(2000)) +'-' as varchar(2000)), t.path) =0 and 
    t.src != 2 
) 
delete CT 
    from CommentPath CT 
    join tree t 
    on t.commentTreeID = CT.ID; 
  • Первый присоединиться используется для перехода вниз по дереву (SRC = 1).
  • Второе соединение используется для перехода на дерево (src = 2).

Когда мы поднимаемся вверх, мы не хотим идти вниз или вверх = = t.src! = 2, это происходит.

  • CHARINDEX (...) защищает нас от петель.

Обратитесь к my solution, который я уже опубликовал. Он также показывает, как обрабатывать таблицу Comment.

И здесь link in SQL Fiddle, чтобы показать пример, который показывает, что он удаляет.

Смежные вопросы