Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Построить текстовую цепочку из дерева / 25 сообщений из 51, страница 1 из 3
27.04.2015, 09:17
    #38945842
X11
X11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
Приветствую всех.

Есть древовидный справочник.

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
CREATE TABLE REGIONS (
    ID          "INT" NOT NULL /* "INT" = INTEGER */,
    PARENT      "INT" NOT NULL /* "INT" = INTEGER */,
    NAME        STRING50 NOT NULL COLLATE PXW_CYRL /* STRING50 = VARCHAR(50) */,
    CCOUNT      "INT" DEFAULT 0 NOT NULL /* "INT" = INTEGER */,
    SORTINDEX   "INT" DEFAULT 0 NOT NULL /* "INT" = INTEGER */,
    IMAGEINDEX  "INT" DEFAULT -1 NOT NULL /* "INT" = INTEGER */,
    STATEINDEX  "INT" DEFAULT -1 NOT NULL /* "INT" = INTEGER */,
    FULLPATH    STRING255 NOT NULL COLLATE PXW_CYRL /* STRING255 = VARCHAR(255) */);



Эта структура осталась ещё от купленных давно компонент FibExTree.
Менять не стал - удобно.

получается справочник районов, т.е. примерно так: Беларусь->Минск->Боровцы.

Таблица показывает пользователю только Боровцы.
Есть процедура на клиенте, которая строит указанную цепочку в Calculated поле, но хотелсь бы на сервере и максимально быстрый алгоритм.
В поле FULLPATH живёт вот такая цепочка "2775.141.2776.187.", т.е. цепочка из ID, 2775 - это корневой узел.

Помогите, пожалуйста, построить на сервере, но чтобы максимально быстро и эффективно тоже с использованием вычисляемого поля. Просто я боюсь, что напишу процедуру далеко не самую быструю.

Может быть уже есть готовые решения?

Спасибо.
...
Рейтинг: 0 / 0
27.04.2015, 09:17
    #38945843
X11
X11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
Забыл добавить: Firebird 2.5.4
...
Рейтинг: 0 / 0
27.04.2015, 09:21
    #38945847
wadman
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
Индексы-то есть?
...
Рейтинг: 0 / 0
27.04.2015, 09:22
    #38945849
wadman
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
X11В поле FULLPATH живёт вот такая цепочка "2775.141.2776.187.", т.е. цепочка из ID, 2775 - это корневой узел.
Забавно... Корневой узел сделан позже, чем ветви. Перетаскивать можно или id с потолка взяты?
...
Рейтинг: 0 / 0
27.04.2015, 09:23
    #38945851
X11
X11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
Получается, что мне нужно сделать путь (path)
...
Рейтинг: 0 / 0
27.04.2015, 09:26
    #38945854
X11
X11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
wadmanX11В поле FULLPATH живёт вот такая цепочка "2775.141.2776.187.", т.е. цепочка из ID, 2775 - это корневой узел.
Забавно... Корневой узел сделан позже, чем ветви. Перетаскивать можно или id с потолка взяты?

в программе есть возможность переносить выделенные узлы
...
Рейтинг: 0 / 0
27.04.2015, 09:26
    #38945855
X11
X11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
wadman,

да, конечно, но это пока что неважно же
...
Рейтинг: 0 / 0
27.04.2015, 09:27
    #38945856
wadman
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
Вот процедура путь добывает, но по именам.
Id = BigInt, varchar-ы тоже были доменными типами, переделал руками.
Код: sql
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.
26.
27.
28.
29.
30.
31.
32.
33.
SET TERM ^ ;

create or alter procedure GET_OBJECT_PATH (
    ID ID)
returns (
    PATH VARCHAR(4096))
as
declare variable APATH VARCHAR(255);
declare variable AID type of ID;
begin
    select pid, name from object where id = :id into :aid, :apath;
    while (apath is not null) do begin
        if (path is not null) then
            path = apath || ' \ ' || path;
        else
            path = apath;
        if (aid is not null) then
            select pid, name from object where id = :aid into :aid, :apath;
        else
            apath = null;
    end
    if (:path is not null) then suspend;
end
^

SET TERM ; ^

COMMENT ON PROCEDURE GET_OBJECT_PATH IS
'Возвращает путь до объекта';

/* Following GRANT statetements are generated automatically */

GRANT SELECT ON OBJECT TO PROCEDURE GET_OBJECT_PATH;

...
Рейтинг: 0 / 0
27.04.2015, 09:28
    #38945857
X11
X11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
Сейчас пытаюсь вникнуть в CTE и рекурсивные запросы - надеюсь, на правильном пути. Но до сего момента не использовал и не имею представления об этом пока что ничего.
...
Рейтинг: 0 / 0
27.04.2015, 09:46
    #38945884
X11
X11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
Вот что у меня получилось

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
with recursive
        r as(
            select id, parent, name
            from regions
            where parent = 0

            union all

            select s.id, s.parent, r.name||'>'||s.name
            from regions s join r on s.parent=r.id
        )
        select name from r
        where r.id=187



http://www.sqlbooks.ru/printarticle.aspx?part=02&file=sql200509
14053226

правда, не сам допёр
...
Рейтинг: 0 / 0
27.04.2015, 09:52
    #38945894
Симонов Денис
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
X11,

боюсь это далеко не самое эффективное решение. Ибо сначала будет построено дерево по всем записям, а только затем произойдёт фильтрация. Попробуй построить наоборот, т.е. от текущего узла к корню. Путь потом можно инвертировать функцией reverse
...
Рейтинг: 0 / 0
27.04.2015, 09:55
    #38945902
DarkMaster
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
Симонов ДенисПуть потом можно инвертировать функцией reverse

Та ну нафиг. 123-456 после REVERSE() 654-321 будет ;)
...
Рейтинг: 0 / 0
27.04.2015, 09:57
    #38945905
X11
X11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
Симонов ДенисX11,

боюсь это далеко не самое эффективное решение. Ибо сначала будет построено дерево по всем записям, а только затем произойдёт фильтрация. Попробуй построить наоборот, т.е. от текущего узла к корню. Путь потом можно инвертировать функцией reverse

так я и строю от текущего, т.е. последнего узла к корню

Цепочка: "2775.141.2776.187.", 2775 - корень
я строю от 187
...
Рейтинг: 0 / 0
27.04.2015, 09:58
    #38945908
X11
X11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
Симонов ДенисИбо сначала будет построено дерево по всем записям

Код: sql
1.
2.
3.
select id, parent, name
            from regions
            where parent = 0



только по корневым
...
Рейтинг: 0 / 0
27.04.2015, 09:58
    #38945910
Симонов Денис
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
DarkMaster,

ммм... значит надо ещё подумать
...
Рейтинг: 0 / 0
27.04.2015, 10:00
    #38945911
X11
X11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
Сейчас проблема вставить рекурсивный запрос в селективную хранимую процедуру

Код: sql
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.
26.
27.
28.
29.
SET TERM ^ ;

create or alter procedure SP_GET_FULL_REGION (
    ID_REGION type of column REGIONS.ID)
as
declare variable RES varchar(1024) collate PXW_CYRL;
BEGIN
FOR SELECT NAME FROM
  (WITH RECURSIVE
        R AS(
            SELECT ID, PARENT, NAME
            FROM REGIONS
            WHERE PARENT = 0 OR (PARENT IS NULL)

            UNION ALL

            SELECT S.ID, S.PARENT, R.NAME||'>'||S.NAME
            FROM REGIONS S JOIN R ON S.PARENT=R.ID)
        SELECT SUBSTRING(NAME FROM 1 FOR 1024) NAME FROM R
        WHERE R.ID = :ID_REGION)

        INTO :RES
        DO


  SUSPEND;
END^

SET TERM ; ^



ничего не возвращает, т.е. процедура как бы не селективная получается
...
Рейтинг: 0 / 0
27.04.2015, 10:08
    #38945922
Симонов Денис
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
X11Вот что у меня получилось

если нужно действительно нужно отфильтровать только от корня то вот так

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
with recursive
        r as(
            select id, parent, name
            from regions
            where parent = 0 and id = 187

            union all

            select s.id, s.parent, r.name||'>'||s.name
            from regions s join r on s.parent=r.id
        )
        select name from r



будет эффективней. Ибо в рекурсивные запросы предикаты не проталкиваются
...
Рейтинг: 0 / 0
27.04.2015, 10:13
    #38945924
X11
X11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
Симонов Денисесли нужно действительно нужно отфильтровать только от корня то вот так

нет, мне надо не от корня, а наоборот - от указанного текущего узла, и вверх до корня
...
Рейтинг: 0 / 0
27.04.2015, 10:14
    #38945927
X11
X11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
и этот запрос пустой

Код: sql
1.
2.
3.
SELECT ID, PARENT, NAME
            FROM REGIONS
            WHERE PARENT = 0 and ID = 187



т.к. таких записей просто нет в таблице
...
Рейтинг: 0 / 0
27.04.2015, 10:19
    #38945931
X11
X11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
чтобы легче было представить:





"ХАРЬКОВ>Город>САЛТОВКА>524м/р"

вот код

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
WITH RECURSIVE
        R AS(
            SELECT ID, PARENT, NAME
            FROM REGIONS
            WHERE PARENT = 0

            UNION ALL

            SELECT S.ID, S.PARENT, R.NAME||'>'||S.NAME
            FROM REGIONS S JOIN R ON S.PARENT=R.ID)
        SELECT SUBSTRING(NAME FROM 1 FOR 1024) NAME FROM R
        WHERE R.ID = 2780
...
Рейтинг: 0 / 0
27.04.2015, 10:26
    #38945939
Симонов Денис
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
X11,

ну тогда надо разворачивать построение дерева. Я же говорю предикаты не проталкиваются. Будет построено дерево целиком и только потом к нему будет прилеплен фильтр. Т.е. по хорошему должно быть как-то так

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
with recursive r (code_horse, code_parent, name) as (
  select
    id, parent, name
  from regions
  where id=187
  union all
  select
    regions .id,
    regions.parent,
    regions.name
 from r join regions on regions.parent = r.id
 where r.parent > 0
)
select
  list(name, '>') as path
from r
...
Рейтинг: 0 / 0
27.04.2015, 10:27
    #38945940
X11
X11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
wadman, Ваш код вызывает

Arithmetic overflow




SQL
Код: sql
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.
26.
SET TERM ^ ;

create or alter procedure SP_GET_FULL_TYPE (
    ID "INT")
returns (
    PATH STRING1000)
as
declare variable APATH varchar(255);
declare variable AID integer;
BEGIN
    SELECT ID, NAME FROM TYPES WHERE ID = :ID INTO :AID, :APATH;

    WHILE (APATH IS NOT NULL) DO BEGIN
        IF (PATH IS NOT NULL) THEN
            PATH = APATH || '>' || PATH;
        ELSE
            PATH = APATH;
        IF (AID IS NOT NULL) THEN
            SELECT ID, NAME FROM TYPES WHERE ID = :AID INTO :AID, :APATH;
        ELSE
            APATH = NULL;
    END
    IF (:PATH IS NOT NULL) THEN SUSPEND;
END^

SET TERM ; ^



цепочка небольшая - 2-3 узла, длина поля name - 20 символов
...
Рейтинг: 0 / 0
27.04.2015, 10:28
    #38945942
Симонов Денис
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
Симонов Денис,

Код: sql
1.
with recursive r (code_horse, code_parent, name) as (...


копипаста от другого запроса должно быть так
Код: sql
1.
with recursive r (id, parent, name) as (...
...
Рейтинг: 0 / 0
27.04.2015, 10:31
    #38945947
X11
X11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
Симонов Денис
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
with recursive r (code_horse, code_parent, name) as (
  select
    id, parent, name
  from regions
  where id=187
  union all
  select
    regions .id,
    regions.parent,
    regions.name
 from r join regions on regions.parent = r.id
 where r.parent > 0
)
select
  list(name, '>') as path
from r



твой код с ошибками

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
with recursive r (code_horse, code_parent, name) as (
  select
    id, parent, name
  from regions
  where id=187
  union all
  select
    regions .id,
    regions.parent,
    regions.name
 from r join regions on regions.parent = r.code_horse
 where code_parent > 0
)
select
  list(name, '>') as path
from r



и в результате вместо цепочки выдаёт только название текущего узла, где ID = 187
...
Рейтинг: 0 / 0
27.04.2015, 10:33
    #38945950
wadman
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Построить текстовую цепочку из дерева
X11цепочка небольшая - 2-3 узла, длина поля name - 20 символов
Предлагаю пройтись дебаггером.
...
Рейтинг: 0 / 0
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Построить текстовую цепочку из дерева / 25 сообщений из 51, страница 1 из 3
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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