Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 как сделать запрос ?....  [new]
Winnipuh
Member [заблокирован]

Откуда: Київ
Сообщений: 10428
упрощеннно говоря задача состояит в следующем:
етсь таблица, в которой представлено простое двухуровневое дерево

create table t(id in, p_id int, type int)

p_id - парент

в процедуре есть рабочая таблица с идентификаторами

create table w(id in)

в которой могут быть вперемешку иды как родителей, так и потомков.

Надо: удалить из w все записи с ид родителей и потомков, если в w нет хотя бы одного потомка этого родителя.

Т.е. если в t

1  0  0
2  1  0 
3  1  0
4  0  0 
5  4  0 
6  4  0 
7  0  0 

и в w

1
2
5
6

то записи с 1,2 должны быть удалены



то
24 июн 09, 16:06    [7338734]     Ответить | Цитировать Сообщить модератору
 Re: как сделать запрос ?....  [new]
Паганель
Member

Откуда: Винница
Сообщений: 22552
Автор, ну Вы же далеко не первый день на форуме,
что же Вы не оформили свой вопрос согласно Рекомендациям

Особенно мне непонятно, в какой именно части задачи у Вас возникли затруднения
24 июн 09, 16:32    [7338997]     Ответить | Цитировать Сообщить модератору
 Re: как сделать запрос ?....  [new]
Winnipuh
Member [заблокирован]

Откуда: Київ
Сообщений: 10428
Паганель
Автор, ну Вы же далеко не первый день на форуме,
что же Вы не оформили свой вопрос согласно Рекомендациям

Особенно мне непонятно, в какой именно части задачи у Вас возникли затруднения


спешил ....

проблема в запросе к таблице w

delete from w where ....

не соображу, как красиво сделать удаление
24 июн 09, 16:37    [7339040]     Ответить | Цитировать Сообщить модератору
 Re: как сделать запрос ?....  [new]
Паганель
Member

Откуда: Винница
Сообщений: 22552
готовое решение от меня не дождетесь

шаг 0: давайте не будем забиваться на двухуровневость

шаг 1: сотворите cte содержащее id и путь
+ ну типа так как-то
declare @t table(id int, p_id int)
insert into @t(id, p_id)
select 1, 0 union all
select 2, 1 union all
select 3, 1 union all
select 4, 0 union all
select 5, 4 union all
select 6, 4 union all
select 7, 0

;with c as (
  select id
        ,cast(str(id) as varchar(max)) as path
    from @t
   where p_id = 0 -- or not exists children
   union all
  select t.id
        ,c.path + str(t.id)
    from @t t
    join c on c.id = t.p_id
)
select *
  from c
шаг 2: сотворите следующий cte со всеми родителями,
для кого exists (select потомок по критерию like путь и not exists (select он же в таблице w))

шаг 3: сотворите следующий cte со всеми потомками родителей, найденных на шаге 2 (легко, по like пути)

шаг 4: union all результатов 2-го и 3-го шагов даст id-шки тех, кого надо удалить
24 июн 09, 16:56    [7339222]     Ответить | Цитировать Сообщить модератору
 Re: как сделать запрос ?....  [new]
Winnipuh
Member [заблокирован]

Откуда: Київ
Сообщений: 10428
Паганель
готовое решение от меня не дождетесь

шаг 0: давайте не будем забиваться на двухуровневость

шаг 1: сотворите cte содержащее id и путь+
+ ну типа так как-то
declare @t table(id int, p_id int)
insert into @t(id, p_id)
select 1, 0 union all
select 2, 1 union all
select 3, 1 union all
select 4, 0 union all
select 5, 4 union all
select 6, 4 union all
select 7, 0

;with c as (
  select id
        ,cast(str(id) as varchar(max)) as path
    from @t
   where p_id = 0 -- or not exists children
   union all
  select t.id
        ,c.path + str(t.id)
    from @t t
    join c on c.id = t.p_id
)
select *
  from c
шаг 2: сотворите следующий cte со всеми родителями,
для кого exists (select потомок по критерию like путь и not exists (select он же в таблице w))

шаг 3: сотворите следующий cte со всеми потомками родителей, найденных на шаге 2 (легко, по like пути)

шаг 4: union all результатов 2-го и 3-го шагов даст id-шки тех, кого надо удалить


спасибо... буду исследовать, единственное - cte не очень резво работает на
боьших объемах, скажем если в таблице 1 млн записей
24 июн 09, 17:03    [7339285]     Ответить | Цитировать Сообщить модератору
 Re: как сделать запрос ?....  [new]
Паганель
Member

Откуда: Винница
Сообщений: 22552
Winnipuh
единственное - cte не очень резво работает на
боьших объемах, скажем если в таблице 1 млн записей
Ну и что, это ж раз в квартал надо, в 2 часа ночи первого числа квартала, правда?
Так что четыре раза в год по ночам по 5 минут сервер пусть уж потрудится, ничего ему не сделается.
24 июн 09, 17:07    [7339336]     Ответить | Цитировать Сообщить модератору
 Re: как сделать запрос ?....  [new]
Winnipuh
Member [заблокирован]

Откуда: Київ
Сообщений: 10428
Паганель
Winnipuh
единственное - cte не очень резво работает на
боьших объемах, скажем если в таблице 1 млн записей
Ну и что, это ж раз в квартал надо, в 2 часа ночи первого числа квартала, правда?
Так что четыре раза в год по ночам по 5 минут сервер пусть уж потрудится, ничего ему не сделается.


не, это может понадобиться юзеру десятки раз в день, и производительность д.б.
приличной.
24 июн 09, 17:29    [7339503]     Ответить | Цитировать Сообщить модератору
 Re: как сделать запрос ?....  [new]
Паганель
Member

Откуда: Винница
Сообщений: 22552
юзер оперирует миллионными деревьями десятки раз в день?
тяжело...

придется Вам, наверное, подумать над тем, чтобы делать это удаление в хранимках,
которые меняют содержимое исходных таблиц
ну чтобы оперировать не всем деревом, а только его кусочком,
который затрагивается текущим изменением
плюс блокировать, наверное, затрагиваемые (и связанные с ними) данные надо
больше ничем помочь не могу
24 июн 09, 17:35    [7339549]     Ответить | Цитировать Сообщить модератору
 Re: как сделать запрос ?....  [new]
iap
Member

Откуда: Москва
Сообщений: 46975
Winnipuh
Паганель
Winnipuh
единственное - cte не очень резво работает на
боьших объемах, скажем если в таблице 1 млн записей
Ну и что, это ж раз в квартал надо, в 2 часа ночи первого числа квартала, правда?
Так что четыре раза в год по ночам по 5 минут сервер пусть уж потрудится, ничего ему не сделается.


не, это может понадобиться юзеру десятки раз в день, и производительность д.б.
приличной.
Значит, надо хранить в таблице дополнительные связи, а не только с родителем.
Возможно, и маршрут от самого корня по узлам хранить в каком-то виде.
Тогда можно надеяться быстро установить наличие/отсутствие потомков без навигации по дереву.
Заполнять это(и) вспомогательное(ы) поле(я) в триггерах.
Чудес-то не бывает!
24 июн 09, 17:37    [7339564]     Ответить | Цитировать Сообщить модератору
 Re: как сделать запрос ?....  [new]
Anddros
Member

Откуда:
Сообщений: 1077
Если дерево двухуровневое, то никакой рекурсии не надо. Все проще.
declare @t table(id int, p_id int)
insert into @t(id, p_id)
select 1, 0 union all
select 2, 1 union all
select 3, 1 union all
select 4, 0 union all
select 5, 4 union all
select 6, 4 union all
select 7, 0

declare @w table(id int)
insert into @w(id)
select 1 union all
select 2 union all
select 5 union all
select 6
 
delete @w
from @w w 
inner join @t t on w.id=t.id
inner join @t t2 on t.p_id=t2.p_id
where not exists(select 1 from @w w2 where w2.id=t2.id)

Если с индексами все в порядке и потомки у одного родителя исчисляются не тысячами, то работать будет. Если нет - то нет. :)
24 июн 09, 18:18    [7339848]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить