powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Where с учётом иерархии
13 сообщений из 13, страница 1 из 1
Where с учётом иерархии
    #32510265
Nikola18
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Интересует мнение сообщества во по какому вопросу:
есть таблица с иерархией типа
CREATE TABLE TA (ID INTEGER, PARENTID INTEGER, COLUMN1 INTEGER);
Как получить все элементы таблицы удовлетворяющие условию,
наложенному на поле COLUMN1 или являющиеся родителями таких записей?

Ограничения:
1. Условие формируется динамически от действий пользователя.
2. Реально таблицы разные с разным набором полей, изначально неизвестным.
    Их объединяет только названия ID и PARENTID.
3. Уровень вложения иерархии также неизвестен, но допускается его ограничение.

P.S.:
Я перечитал все посты на тему рекурсии и дерева, но везде речь идёт о предопределённых таблицах.

P.P.S.:
И что могут сказать приближенные к разработчикам Firebird/Yaffil на такой запрос в смысле его эффективности:
Select TA.ID, TA.PARENTID, TA.COLUMN1 from TA
Where (((cast(TA.COLUMN1 as VarChar(250)) = 'XXXXXXX'))
or exists (
  select ID from TA TA00
  left outer join TA TA01 on TA00.ID = TA01.PARENTID
  left outer join TA TA02 on TA01.ID = TA02.PARENTID
  left outer join TA TA03 on TA02.ID = TA03.PARENTID
  left outer join TA TA04 on TA03.ID = TA04.PARENTID
  left outer join TA TA05 on TA04.ID = TA05.PARENTID
  where (TA.ID = TA00.PARENTID) and (
        ((cast(TA00.COLUMN1 as VarChar(250)) = 'XXXXXXX'))
    or ((cast(TA01.COLUMN1 as VarChar(250)) = 'XXXXXXX'))
    or ((cast(TA02.COLUMN1 as VarChar(250)) = 'XXXXXXX'))
    or ((cast(TA03.COLUMN1 as VarChar(250)) = 'XXXXXXX'))
    or ((cast(TA04.COLUMN1 as VarChar(250)) = 'XXXXXXX'))
    or ((cast(TA05.COLUMN1 as VarChar(250)) = 'XXXXXXX'))
))) order by TA.COLUMN1 asc
...
Рейтинг: 0 / 0
Where с учётом иерархии
    #32510522
IGORRR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Попробовать можно так:
делаешь табличку
create table result (
id integer,
parentid integer);


Делашь ХП
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
set term ^;
alter procedure someproc (param integer)
as
declare variable id integer;
declare variable parentid integer;
declare variable parentid2 integer;
declare variable fl1 integer;
begin
FOR
   select id, parentid from ta where column1 = :param into :id, :parentid
 do
 begin
   insert into result (id, parentid) values (:id, :parentid);
   fl1 =  1 ;
   while(fl1 =  1 )
   do
   begin
     select id, parentid from ta where id = :parentid into :id, :parentid2;
     insert into result (id, parentid) values (:id, :parentid2);
     if(parentid2 is null) then fl1 =  0 ;
     parentid = parentid2;
   end
 end
end
^
set term ;^
Дальше на вход в someproc подаешь свой признак и получаешь в табличке result свои индексы.
А потом уже выбираешь целые поля из TA, основываясь на индексах из result.
Посмотри. У меня все отработало ОК
...
Рейтинг: 0 / 0
Where с учётом иерархии
    #32510535
Scream
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А вложенным SELECT `ом не пробовал?
Или с помощью UNION ?
...
Рейтинг: 0 / 0
Where с учётом иерархии
    #32510620
FreemanZAV
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Возможно так:
Запрос можно разбить на 2 части
1. элементы таблицы удовлетворяющие условию,
наложенному на поле COLUMN1

Код: plaintext
1.
Select TA.ID, TA.PARENTID, TA.COLUMN1 from TA
Where (((cast(TA.COLUMN1 as VarChar( 250 )) = 'XXXXXXX')) 
2. или являющиеся родителями таких записей
Код: plaintext
1.
2.
3.
Select TP.ID, TP.PARENTID, TP.COLUMN1 from TA TP
INNER JOIN TA TC ON (TP.ID=TC.PARENT_ID)
WHERE (((cast(TP.COLUMN1 as VarChar( 250 )) <> 'XXXXXXX'))
AND (((cast(TC.COLUMN1 as VarChar( 250 )) = 'XXXXXXX')) 
Объединяем результаты запроса
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
Select TA.ID, TA.PARENTID, TA.COLUMN1 from TA
Where (((cast(TA.COLUMN1 as VarChar( 250 )) = 'XXXXXXX'))
UNION ALL
Select TP.ID, TP.PARENTID, TP.COLUMN1 from TA TP
INNER JOIN TA TC ON (TP.ID=TC.PARENT_ID)
WHERE (((cast(TP.COLUMN1 as VarChar( 250 )) <> 'XXXXXXX'))
AND (((cast(TC.COLUMN1 as VarChar( 250 )) = 'XXXXXXX'))
 
...
Рейтинг: 0 / 0
Where с учётом иерархии
    #32510742
Nikola18
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
2IGORRR: Всё бы нормально, но в соответствии с ограничением 1 условие where column1 = :param не прокатит.

2FreemanZAV: Запрос с использованием UNION работает похоже дольше по сравнению с описанным мною запросом, это я уже проверял.

2Scream: А это как - вложенным SELECT`ом?
...
Рейтинг: 0 / 0
Where с учётом иерархии
    #32510764
FreemanZAV
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Надо не просто UNION , а именно UNION ALL
...
Рейтинг: 0 / 0
Where с учётом иерархии
    #32510766
IGORRR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Nikola18, я тебя не понял,
> в соответствии с ограничением 1 условие where column1 = :param не прокатит.
param - это же входной параметр в ХП, где бы у тебя не формировалось условие на клиенте или сервере - вызывай ХП с этим параметром и все..?
...
Рейтинг: 0 / 0
Where с учётом иерархии
    #32510791
Nikola18
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
:param - да, но вот column1 вовсе может быть и не column1, а например: ((column1=1) or (column55=55)) и т.д.
ВСЁ условие генерится в зависимости от пользователя, на каком столбце он кликнет такой реквизит и будет, как в Excelе.
...
Рейтинг: 0 / 0
Where с учётом иерархии
    #32510818
Nikola18
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
2FreemanZAV: Дело в том, что при использовании UNION происходит неоднократное чтение всей исходной таблицы. И чем больше UNIONов тем больше проходов. Поэтому и рекомендуется при возможности избегать объединения и использовать 1 select.
А вообще сейчас протестил, то, что только что написал - так и есть.

2ALL: Приведённый в первом моём посте запрос меня бы устроил, но я не уверен в том, как он будет себя вести на базе порядка от 200 тыс. записей и от 5 уровней вложенности.
Явно недостаёт возможности CONNECT BY :(
...
Рейтинг: 0 / 0
Where с учётом иерархии
    #32510822
FreemanZAV
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Nikola18 рекомендуется при возможности избегать объединения и использовать 1 select
А при использовании exists вложенный запрос выполняется на каждую запись основного запроса, поэтому тормоза могут быть еще больше (но могут и не быть ).
...
Рейтинг: 0 / 0
Where с учётом иерархии
    #32510831
FreemanZAV
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А зачем так много LEFT JOIN в подзапросе? Ведь достаточно определить имеет ли родительский узел потомка, удовлетворяющего условиям.
...
Рейтинг: 0 / 0
Where с учётом иерархии
    #32510866
Nikola18
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
А как вывести вот такое дерево:
1-ый_родитель_ НЕ удовлетворяющий_условию
+-- 2-ой_родитель_ НЕ удовлетворяющий_условию
| +-- 3-ий_родитель_ НЕ удовлетворяющий_условию
| | +-- 4-ый_родитель_ НЕ удовлетворяющий_условию
| | | +-- 5-ая_запись_удовлетворяющая_условию
...
Рейтинг: 0 / 0
Where с учётом иерархии
    #32510867
Мимопроходящий
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
13 сообщений из 13, страница 1 из 1
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Where с учётом иерархии
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]