Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2002.06.24;
Скачать: [xml.tar.bz2];

Вниз

Выборка из дерева   Найти похожие ветки 

 
Mirovodin   (2002-05-25 15:05) [0]

Структура таблицы (стандартное дерево)

idx | parentidx | Name |
----------------------------
1 | Null | ВСЕ |
2 | 1 | глава1 |
3 | 2 | подглава |



Необходим запрос выбирающий все элементы Name
начиная с указанного parentID. Наверное необходим рекурсивный
вызов (как при поиске вайлов начиная с каталога), но
SQL изучаю не давно, по этому ... спрашиваю.
Да вложенность, 4-5 уровнней.


 
Delirium   (2002-05-25 15:28) [1]

IMHO: Рекурсивная процедура пишет записи во временную таблицу


 
Некий   (2002-05-26 02:51) [2]

Не понял!
А "WHERE parentidx >= :Myidx" - не подходит?


 
Mirovodin   (2002-05-26 11:19) [3]

2 Некий. Так конечно не подходит т.к. индекс может индексы могут быть совершенно разные, т.е. нужно рекурсию написать но в этом то вся и проблема - плохо знаю SQL.

2 Delirium Нужен пример, я и так понимаю что такое врем-е таблицы, просто ни разу не пользовался ... а в книгах нет :(


 
Mirovodin   (2002-05-27 19:54) [4]

Народ, что ни кто не работал с древовидным представлением данных !!!???


 
OlegE   (2002-05-28 09:49) [5]

На www.ibase.ru есть несколько статей с примерами.


 
SergSuper   (2002-05-28 10:09) [6]

2 Mirovodin
Насчет временных таблиц можно почитать в Book On-Line(это такой хелп к MS SQL) по теме Temporary Tables. Да и в любой книжке должно быть.
А вообще это неплохая задачка для изучающих SQL недавно. Пишется это строчек в 10, используя цикл while, а рекурсия здесь совершенно не нужна (как впрочем и вообще в SQL)


 
xGrey   (2002-05-28 11:33) [7]

Процедура по "вытаскиванию" ветки дерева:
MyId - idx родителя ветки;
TmpTbl - временная таблица;
Table_Name - имя Вашей таблицы.
Код под DB2, но смысл, думаю, будет понятен:

WITH TmpTbl (idx, name, parentidx) as
(select idx, name_name, parentidx
fromTable_Name where idx=MyId
Union All
select Table_Name.idx, Table_Name.name, Table_Name.parentidx
from TmpTbl , Table_Name
where TmpTbl.idx= Table_Name.parentidx)

select * from TmpTbl


 
Mirovodin   (2002-05-28 23:09) [8]

1-е нужен только вариант с использованием синтаксиса SQL 7, т.е. функции пользователя не подойдут.
2-е прочитав док-ю я понял, что нужно использовать курсоры и циклы While exests ...

Может я не очень корректно поставил вопрос, но нужно найти как бы все файлы начиная с данного каталога - это по аналогии с FindFist, FindNext. Только в место файлов выступают записи хранящиеся в древ-й структуре.




 
Cobalt   (2002-05-29 02:22) [9]

Вот, у меня что-то такое получилось:

Select Name from MYTABLE
where MyProc(Idx, 3) <>0

Create Procedure MyProc (InpId integer, InpParent integer)
RETURNS (Res integer)
AS DECLARE VARIABLE i1 integer;
BEGIN
SELECT parentidx FROM MYTABLE
WHERE idx = :InpId
INTO i1;
IF (i1 = 0)
THEN BEGIN
Res = 0;
SUSPEND;
END
IF (i1 = InpParent)
THEN BEGIN
Res = 1;
SUSPEND;
END
EXECUTE PROCEDURE MyProc :i1, :InpParent RETURNING_VALUES :res;
SUSPEND;
END

вот только select не получается ;((
Грит, что не может найти function MyProc (IB 5.1.1.680)


 
Владислав   (2002-05-29 06:27) [10]

http://sdm.viptop.ru/articles/sqltrees.html
Эту ссылку видели?
Если это в проекте, то не еще поздно :)


 
SergSuper   (2002-05-29 10:33) [11]

2 Mirovodin
курсоры то зачем? забудьте про них пока

надо делать примерно так:
declare @id int -- заданный элемент

create table #t(id int, level int) -- временная таблица
declare @L int -- текущий уровень элементов
set @L=0
insert #t select @id, 0

while exists(select * from #t t, tbl x where t.id=x.parentidx and t.level=@L)
begin
insert #t
select x.idx, @L+1
from #t t, tbl x
where t.id=x.parentidx and t.level=@L
set @L=@L+1
end

select x.Name from #t t, tbl x where t.id=x.idx


я не проверял, возможны ошибки, главное - поймите принцип




 
Delirium   (2002-05-29 11:31) [12]

Есть таблица Test (id int, Pid int, Val char(10))
далее запрос и рекурсивная процедура, как я и говорил. Можно в принципе и без курсора обойтись - удалением из другой временной таблицы, но это IMHO не оптимальный путь.

select top 0 * into #Tmp from Test
exec MyProc 1
select * from Test where id=1
union all
select * from #Tmp



CREATE procedure MyProc @paramID int
AS
declare @id int
declare @Pid int
declare @Val char(10)
declare curTest cursor local scroll
for select * from Test
where Pid=@ParamID
open curTest
fetch first from curTest into @id, @Pid, @Val
while (@@FETCH_STATUS=0)
begin
insert #Tmp values (@id, @Pid, @Val)
exec MyProc @id
fetch next from curTest into @id, @Pid, @Val
end
close curTest
deallocate curTest


 
Просто так   (2002-05-29 11:41) [13]

Хм... Не знал что в MSSQL так проблемно дерево построить... на Oracle гораздо проще...


 
Delirium   (2002-05-29 11:48) [14]

> Просто так

Это чем-же на Oraclе проще ?


 
fnatali   (2002-05-29 12:05) [15]

Delirium © (29.05.02 11:48)
На Oracle это будет выглядеть так:
select idx from dept start with idx=:par1 connect by prior idx=parentidx
Один оператор - очень удобно


 
Sam3D   (2002-05-29 12:18) [16]

В свое время писал для IB процедурку, которая возвращала иерархию вида
1. Param1
1.1. Param2
1.1.1. Param3
1.2. Param4
1.2.1. Param5
1.2.2. Param6... и т.д.

Думаю, для MSSQL не составит особого труда переписать в случае надобности. Конечно, за оптимальность приведенного ниже кода не ручаюсь, но, тем не менее, работало все как надо...

SET TERM !!;
CREATE PROCEDURE BUILD_HIERARCHY
(PARM SMALLINT, INIHIER VARCHAR(40) CHARACTER SET WIN1251, CNT SMALLINT)
RETURNS
(PARMID SMALLINT, HIERNUM VARCHAR(40) CHARACTER SET WIN1251)
AS
DECLARE VARIABLE NEWHIER VARCHAR(40);
DECLARE VARIABLE PPARM SMALLINT;
DECLARE VARIABLE PARMCOUNT SMALLINT;
DECLARE VARIABLE OLDCOUNT SMALLINT;
BEGIN
PARMID = PARM;
NEWHIER = INIHIER || CNT || ".";
HIERNUM = NEWHIER;
SUSPEND;
PARMCOUNT = 1;
FOR SELECT ID
FROM PAIRS
WHERE PARENT = :PARM
INTO :PPARM
DO
BEGIN
IF (EXISTS (SELECT * FROM BUILD_HIERARCHY :PPARM, :NEWHIER, :PARMCOUNT))) THEN BEGIN
OLDCOUNT = PARMCOUNT;
FOR SELECT * FROM BUILD_HIERARCHY :PPARM, :NEWHIER, :PARMCOUNT) INTO :PARMID, :HIERNUM
DO BEGIN
PARMCOUNT = PARMCOUNT+1;
SUSPEND;
END
PARMCOUNT = OLDCOUNT + 1;
END
END
END!!
SET TERM ;!!

У процедуры три параметра вызова: идентификатор корневого элемента, строка, выводимая перед каждым номером иерархии, и начальный номер иерархии.
Возвращает процедура иерархический номер и идентификатор элемента, которому он соответствует.
Таблица, по которой строится иерархия называется PAIRS и имеет два поля - ID и PARENT. Названия говорят сами за себя.
Удачи!


 
Delirium   (2002-05-29 14:04) [17]

> fnatali

Да, в синтаксис Transact SQL не заложено таких операторов, однако это не недостаток, а отсутствие избыточных средств. Ведь ничего не стоит написать данную функцию самостоятельно, причём, возможно - более гибко.


 
fnatali   (2002-05-29 14:17) [18]

>Delirium © (29.05.02 14:04)
Согласна. Но если уж в Оракл предусмотрели подобную конструкцию, то почему бы ею не пользоваться? :)


 
SergSuper   (2002-05-29 15:22) [19]

2 Delirium
Ну-ну
попробуйте написать такую функцию

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


 
Delirium   (2002-05-29 19:49) [20]

> SergSuper

Напишу - оплатишь?


 
SergSuper   (2002-05-30 09:30) [21]

>Delirium
ага, пивом :)

на самом деле это именно конструкция, потому что она заставляет выполнять запрос циклически, и просто функцией, которая проверяет какое-то условие здесь не обойтись

я сам работаю с MS SQL, но всё-таки надо признать(хоть мне тоже не хочется) что у Oracle возможностей (и не только избыточных) мягко говоря побольше



 
Delirium   (2002-05-30 10:21) [22]

> SergSuper

Конечно, ораклоиды могут радоваться :(
хотя в конкретном случае, если подойти системно и грамотно проработать вопрос, IMHO, вполне можно обойтись может не одной, так двумя - тремя пользовательскими функциями. Причём, повторюсь, если заняться серьёзно (например, добавить временные индексы или попробовать решить задачу посредством SQL-DMO) - можно и производительность довести до оракловского уровня.


 
Mirovodin   (2002-05-31 09:09) [23]

Большое спасибо Delirium, только твой пример и работает. Так что если кому потребуется - процедура работает на 100%, проверялась на SQL 7.0 и SQL 2000. Хотя если писать для 2000 можно избавится от временной таблицы и заюзать функции... На счет остальных примеров - возможно они с ошибками или для других диалектов, но перенести в SQL 7 мне их не удалось.


 
Delirium   (2002-05-31 13:58) [24]

> Mirovodin

Я тут подумал на досуге - получилось красиво и просто:


select * into #tmp from test where id=1

while exists(select * from test
where Pid in (select id from #tmp)
and id not in (select id from #tmp))
insert #tmp select * from test
where Pid in (select id from #tmp)
and id not in (select id from #tmp)

select * from #tmp


И ни каких процедур и курсоров :)


 
Mirovodin   (2002-06-01 11:23) [25]

Большое спасибо Delirium, последний запрос работает на несколько поряднов быстрее (таблица ~5000 записей).



Страницы: 1 вся ветка

Форум: "Базы";
Текущий архив: 2002.06.24;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.51 MB
Время: 0.011 c
3-77284
Meduza
2002-05-27 15:28
2002.06.24
Kak razpoznatj sistemnogo administratora


1-77453
Hermit
2002-06-11 18:15
2002.06.24
Печать TStrings


1-77459
Korona
2002-06-09 21:11
2002.06.24
Как правильно создавать формы?


14-77608
MisterBin
2002-05-16 21:24
2002.06.24
Кто какую музыку слушает когда пишет программу?


1-77397
Dark Elf
2002-06-11 12:25
2002.06.24
Большие числа для RSA





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский