Хитрая выборка из бинарного дерева

Hijem

Доброго времени суток! Помогите пожалуйста разобраться как лучше написать процедуру..Имеется таблица со структурой бинарного дерева:
id naim id_count path  -------------------------------------------------| 1 | k | 0 | k* | 2 | a2 | 1 | k*a2 | 3 | a3 | 1 | k*a3 | 4 | b1 | 2 | k*a2*b1 | 5 | b2 | 3 | k*a3*b2 | 6 | b3 | 4 | k*a2*b1*b3 | 7 | c1 | 1 | k*c1| 8 | c2 | 6 | k*a2*b1*b3*c2и т.д.  -------------------------------------------------
Требуется написать процедуру чтобы по заданому узлу (поле id в таблице) вывести всех его потомков.Например если в параметре задать '2', то вывелись бы строки
id naim id_count path  -------------------------------------------------| 2 | a2 | 1 | k*a2 | 4 | b1 | 2 | k*a2*b1 | 6 | b3 | 4 | k*a2*b1*b3 | 8 | c2 | 6 | k*a2*b1*b3*c2-------------------------------------------------
Пробовал сделать с помощью курсора, но во первых медленно работает, а во вторых теряются строки..Мне намекнули что можно сделать эту процедуру с помощью @@ROWCOUNT, но я не могу понять как(Помогите пожалуйста разобраться!
24 ответа

Hijem

select @@version
?


Hijem

Microsoft SQL Server 2005 - 9.00.1399.06 (Intel X86) Oct 14 2005 00:33:37 Copyright (c) 1988-2005 Microsoft Corporation Developer Edition on Windows NT 5.1 (Build 2600: Service Pack 3)


Hijem

Спасибо, надеюсь разберусь)


Hijem

2Паганель,я может чего не понял, но по-моему тут рекурсивные CTE - из пушки по тараканам Hijem,такое дает верный ответ на ваших данных.
declare @t table (id int, naim varchar(<b>20</b>), id_count int, path varchar(<b>8000</b>))
insert @t
select <b>1</b>,'k', <b>0</b>,'k*' union all
select <b>2</b>,'a2',<b>1</b>,'k*a2' union all
select <b>3</b>,'a3',<b>1</b>,'k*a3' union all
select <b>4</b>,'b1',<b>2</b>,'k*a2*b1' union all
select <b>5</b>,'b2',<b>3</b>,'k*a3*b2' union all
select <b>6</b>,'b3',<b>4</b>,'k*a2*b1*b3' union all
select <b>7</b>,'c1',<b>1</b>,'k*c1' union all
select <b>8</b>,'c2',<b>6</b>,'k*a2*b1*b3*c2'


select * 
from @t t1 join @t t2 on t2.path like t1.path + '%'
where t1.id = <b>2</b>


Hijem

iljy,спасибо, я попробую!Кстати условие для процедуры изменилось тем, что её нужно написать не для MS SQL 2005 а для 2000.. Приведенный выше код подойдет для 2000 версии?


Hijem

Hijem,мой - да, с сте - нет.


Hijem

iljy,я попробовал на реальной таблице,но процедура выводит мне только начальный узел. Подозреваю что конструкция like t1.path + '%' не срабатывает.. Из за чего это может быть?


Hijem

Из-за неправильно заполненного поля path, например


Hijem

Path во всех записях строится из полей naim предков, связаных звездочками.. Как я и описал в примере. По логике должно работать, но может быть есть какие то особые нюансы?


Hijem

Hijem,покажите эти значения (в смысле path)


Hijem

Как я и описал в примере
Давайте пример данных, на которых не работает


Hijem

например есть такие pathНоменклатура*Сигареты*Номенклатура*Сигареты*Балканская звезда* Номенклатура*Сигареты*Сигары*Даннеманн* илиНоменклатура*Сыры* Номенклатура*Сыры*Плавленный* Номенклатура*Сыры*Элитные*Германия*


Hijem

процедура выводит мне только начальный узел
А у меня - не только начальный
declare @t table (id int, naim varchar(<b>20</b>), id_count int, path varchar(<b>8000</b>))
insert @t
select <b>1</b>,'k', <b>0</b>,'Номенклатура*Сигареты*' union all
select <b>2</b>,'a2',<b>1</b>,'Номенклатура*Сигареты*Балканская звезда*' union all
select <b>3</b>,'a3',<b>1</b>,'Номенклатура*Сигареты*Сигары*Даннеманн*'


select t2.* 
from @t t1 join @t t2 on t2.path like t1.path + '%'
where t1.id = <b>1</b>

id naim id_count path
----------- -------------------- ----------- -------------------------------------------
<b>1</b> k <b>0</b> Номенклатура*Сигареты*
<b>2</b> a2 <b>1</b> Номенклатура*Сигареты*Балканская звезда*
<b>3</b> a3 <b>1</b> Номенклатура*Сигареты*Сигары*Даннеманн*

(<b>3</b> row(s) affected)


Hijem

Hijem,
declare @t table (id int identity, path varchar(<b>8000</b>))

insert @t (path)
select 'Номенклатура*Сигареты*' union all
select 'Номенклатура*Сигареты*Балканская звезда*' union all
select 'Номенклатура*Сигареты*Сигары*Даннеманн*' union all
select 'Номенклатура*Сыры*' union all
select 'Номенклатура*Сыры*Плавленный*' union all 
select 'Номенклатура*Сыры*Элитные*Германия*'

select * from @t

select * 
from @t t1 join @t t2 on t2.path like t1.path + '%'
where t1.id in (<b>1</b>,<b>4</b>)
результат
id
Что не так?


Hijem

Действительно, с табличной переменной срабатывает. Но с реальной таблицей почему то не работает(((


Hijem

Hijem,значит у вас в реальной таблице почему-то другие данные.


Hijem

Hijem,у вас кстати поле часом не юникодовское?


Hijem

iljy,Данные именно такие как я в примере скинул.. Я даже извратился и всю таблицу кинул в табличную переменную:) Но результат такой же, выводит только первый узел( Может быть вы подскажете какими еще способами можно решить подобную задачу?


Hijem

iljy,возможно) Но я не знаю как это проверить :[


Hijem

Hijem,у вас не работает запрос, который работать должен. Пока вы не разберетесь почему - искать другие решения можно, но бессмысленно, потому что никаих гарантий что они заработают нет. Вы с алиасами в запросе не напутали?


Hijem

iljy,возможно) Но я не знаю как это проверить :[
select COLUMN_NAME, DATA_TYPE from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = 'Имя таблицы'


Hijem

select COLUMN_NAME, DATA_TYPE from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = 'Имя таблицы'
id	 intnaim	 varcharid_count	intpath	 varchar


Hijem

iljy,С алиасами всё в порядке, я скопировал ваш код. Разумеется название таблицы сменил