powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Рекурсия + временные таблицы
25 сообщений из 30, страница 1 из 2
Рекурсия + временные таблицы
    #33690266
J-Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Народ, это снова я :)
Продолжая разбираться с PostgreSQL наткнулся на сложность, которую уже день не могу разрешить, хоть бьюсь изо всех сил...

Дело в следующем: есть таблица Tasks для хранения информации о заданиях, а также TasksAssosiations для хранения информации о дочерних заданиях. То бишь, если в Task записано два задания с ID = 1, ID = 2, то, зная, что 2 - подтаск 1, в таблице TasksAssosiations будет записано: ParentTaskID = 1, ChildTaskID = 2.

Пишу сейчас ф-цию удаления задания по ID. Хочу удалить все подтаски таска, а потом и этот таск. Но никак не получается найти решение... Если рекурсия плюс временная таблица, то при переходе уже на второй уровень сервак ругается, что такая времнная таблица уже есть (конечно, я создал её на первом уровне):

Код: 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.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
CREATE OR REPLACE FUNCTION "public"."DeleteTask" (taskid integer) RETURNS bit AS
$body$
DECLARE ID1 INTEGER;
DECLARE quan INTEGER;

BEGIN

-- delete next dependency
       -- select all taskids children
CREATE TEMPORARY TABLE tmpIDs AS SELECT TA."ChildTaskID" FROM "TasksAssociations" TA
                               WHERE TA."ParentTaskID" = taskid;
       -- delete all dependencies with taskids children
DELETE FROM "TasksAssociations" WHERE "ParentTaskID" = taskid;

       -- get count of our saved taskids children from our rec
SELECT INTO quan count(*) FROM tmpIDs;
WHILE (quan !=  0 )
LOOP
 SELECT INTO ID1 tmpIDs."ChildTaskID" FROM tmpIDs;
 PERFORM * FROM public."DeleteTask"(ID1);
 DELETE FROM tmpIDs WHERE tmpIDs."ChildTaskID" = ID1;
END LOOP;

DELETE FROM "TasksAssociations" WHERE "ChildTaskID" = ID1;



DELETE FROM "Tasks"
WHERE "TaskID" = taskid;

RETURN  1 ;

END;
$body$
LANGUAGE 'plpgsql' VOLATILE CALLED ON NULL INPUT SECURITY INVOKER;

Если же рекурсия и тип запись(RECORD), то я не знаю, как выбрать из записи SELECT'ом последний ID...:

Код: 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.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
CREATE OR REPLACE FUNCTION "public"."DeleteTask" (taskid integer) RETURNS bit AS
$body$
DECLARE ID1 INTEGER;
DECLARE rec RECORD;
DECLARE quan INTEGER;

BEGIN

-- delete next dependency
       -- select all taskids children
SELECT INTO rec "ChildID" FROM "TasksAssociations" WHERE "ParentTaskID" = taskid;

       -- delete all dependencies with taskids children
DELETE FROM "TasksAssociations" WHERE "ParentTaskID" = taskid;

       -- get count of our saved taskids children from our rec
quan := rec.count;
WHILE (quan !=  0 )
LOOP
 SELECT INTO ID1 "ChildTaskID" FROM rec;
 PERFORM * FROM public."DeleteTask"(ID1);
 DELETE FROM rec WHERE "ChildTaskID" = ID1;
END LOOP;

DELETE FROM "TasksAssociations" WHERE "ChildTaskID" = ID1;



DELETE FROM "Tasks"
WHERE "TaskID" = taskid;

RETURN  1 ;

END;
$body$
LANGUAGE 'plpgsql' VOLATILE CALLED ON NULL INPUT SECURITY INVOKER;

Последний код даже не компилится, ругается на две строчки:

Код: plaintext
1.
2.
3.
 SELECT INTO ID1 "ChildTaskID" FROM rec;
...
 DELETE FROM rec WHERE "ChildTaskID" = ID1;

Видимо, нельзя так делать... Что посоветуете, господа? Я очень надеюсь на ваш опыт, он у вас есть... Не раз мне помогали в, казалось бы, безвыходных ситуациях...


ОГРОМНОЕ спасибо заранее!
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33690342
фффф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Не проще ли на триггеры и каскадные внешние ключи возложить? Тогда достаточно будет просто удалить узел - а остальное пойдет по цепочке
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
create table tasks (id int primary key);
create table tasksass (
  parent int references tasks(id) on delete cascade,
  child  int references tasks(id) on delete cascade
);

CREATE OR REPLACE FUNCTION tr_tasksass_recursive_delete() RETURNS trigger LANGUAGE plpgsql AS $body$
BEGIN
  delete from tasks where id=OLD.child;
  return NEW;
END;
$body$;

CREATE TRIGGER tr_tasksass_recursive_delete AFTER DELETE ON tasksass FOR EACH ROW
  EXECUTE PROCEDURE tr_tasksass_recursive_delete();
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33690793
J-Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Хм... честно говоря, с триггерами дела не имел никогда, но их предназначение мне известно - при определённых изменениях в таблице они активизируются и выполняют какие-то действия. Но мне кажется, то, что Вы предложили, не реализует в полной мере мною задуманное...

Мне нужно при удалении из таблицы Tasks сначала удалить все связи из таблицы TasksAssosiations, а потом удалить этот task из таблицы Tasks. Но при удалении связей из таблицы TasksAssosiations необходимо рекурсивно так же удалить всех "детей" удаляемого таска. Таким образом, имея таблицы:

Код: 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.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
CREATE TABLE "public"."Tasks" (
  "ProjectID" INTEGER NOT NULL, 
  "TaskID" INTEGER DEFAULT nextval(('"public"."tasks_taskid_seq"'::text)::regclass) NOT NULL, 
  "Name" VARCHAR( 50 ), 
  "Custom1" VARCHAR( 50 ), 
  "Custom2" VARCHAR( 50 ), 
  "Custom3" VARCHAR( 50 ), 
  "Remarks" VARCHAR( 255 ), 
  "ActualFundingID" INTEGER, 
  CONSTRAINT "Tasks_pkey" PRIMARY KEY("TaskID"), 
) WITHOUT OIDS;


INSERT INTO "public"."Tasks" ("ProjectID", "TaskID", "Name", "Custom1", "Custom2", "Custom3", "Remarks", "ActualFundingID")
VALUES ( 1 ,  15 , 'f1', NULL, NULL, NULL, NULL,  1 );

INSERT INTO "public"."Tasks" ("ProjectID", "TaskID", "Name", "Custom1", "Custom2", "Custom3", "Remarks", "ActualFundingID")
VALUES ( 1 ,  7 , 'f2', NULL, NULL, NULL, NULL,  1 );

INSERT INTO "public"."Tasks" ("ProjectID", "TaskID", "Name", "Custom1", "Custom2", "Custom3", "Remarks", "ActualFundingID")
VALUES ( 1 ,  8 , 'f3', NULL, NULL, NULL, NULL,  1 );

INSERT INTO "public"."Tasks" ("ProjectID", "TaskID", "Name", "Custom1", "Custom2", "Custom3", "Remarks", "ActualFundingID")
VALUES ( 1 ,  9 , 'f4', NULL, NULL, NULL, NULL,  1 );

INSERT INTO "public"."Tasks" ("ProjectID", "TaskID", "Name", "Custom1", "Custom2", "Custom3", "Remarks", "ActualFundingID")
VALUES ( 1 ,  10 , 'f5', NULL, NULL, NULL, NULL,  1 );

INSERT INTO "public"."Tasks" ("ProjectID", "TaskID", "Name", "Custom1", "Custom2", "Custom3", "Remarks", "ActualFundingID")
VALUES ( 1 ,  11 , 'f6', NULL, NULL, NULL, NULL,  1 );

INSERT INTO "public"."Tasks" ("ProjectID", "TaskID", "Name", "Custom1", "Custom2", "Custom3", "Remarks", "ActualFundingID")
VALUES ( 1 ,  12 , 'f7', NULL, NULL, NULL, NULL,  1 );

INSERT INTO "public"."Tasks" ("ProjectID", "TaskID", "Name", "Custom1", "Custom2", "Custom3", "Remarks", "ActualFundingID")
VALUES ( 1 ,  13 , 'f8', NULL, NULL, NULL, NULL,  1 );

INSERT INTO "public"."Tasks" ("ProjectID", "TaskID", "Name", "Custom1", "Custom2", "Custom3", "Remarks", "ActualFundingID")
VALUES ( 1 ,  14 , 'f9', NULL, NULL, NULL, NULL,  1 );

-- ///////////////////////////////////////////////////////////////////////////////

CREATE TABLE "public"."TasksAssociations" (
  "ParentTaskID" INTEGER NOT NULL, 
  "ChildTaskID" INTEGER NOT NULL, 
  CONSTRAINT "TasksAssociations_pkey" PRIMARY KEY("ParentTaskID", "ChildTaskID"), 
  CONSTRAINT "TasksAssociations_fk" FOREIGN KEY ("ParentTaskID")
    REFERENCES "public"."Tasks"("TaskID")
    MATCH FULL
    ON DELETE RESTRICT
    ON UPDATE NO ACTION
    NOT DEFERRABLE, 
  CONSTRAINT "TasksAssociations_fk1" FOREIGN KEY ("ChildTaskID")
    REFERENCES "public"."Tasks"("TaskID")
    MATCH FULL
    ON DELETE RESTRICT
    ON UPDATE NO ACTION
    NOT DEFERRABLE
) WITHOUT OIDS;

INSERT INTO "public"."TasksAssociations" ("ParentTaskID", "ChildTaskID")
VALUES ( 7 ,  9 );

INSERT INTO "public"."TasksAssociations" ("ParentTaskID", "ChildTaskID")
VALUES ( 7 ,  10 );

INSERT INTO "public"."TasksAssociations" ("ParentTaskID", "ChildTaskID")
VALUES ( 7 ,  13 );

INSERT INTO "public"."TasksAssociations" ("ParentTaskID", "ChildTaskID")
VALUES ( 9 ,  12 );

INSERT INTO "public"."TasksAssociations" ("ParentTaskID", "ChildTaskID")
VALUES ( 15 ,  7 );

INSERT INTO "public"."TasksAssociations" ("ParentTaskID", "ChildTaskID")
VALUES ( 15 ,  8 );

INSERT INTO "public"."TasksAssociations" ("ParentTaskID", "ChildTaskID")
VALUES ( 15 ,  11 );

При удалении таска с ID = 15, мы должны получить данные:

Таблица Tasks(пишу только ID): 9 и 12.
Таблица TasksAssosiations(пишу только ID): TaskParentID = 9, TaskChildID = 12.

Так должно остаться, т.к. у таска 15 дети: 7,8,11, а у таска 7, в свою очередь, дети: 9, 10, 13. И их все рекурсивно надо удалить.

Вот, что необходимо. Имхо, триггер этого не сделает... Хотя... затем я и тут, что знаний недостаточно. Вот, пытаю счастья... Надеюсь, поможете.

Езё раз спасибо заранее!
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33690796
4321
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
каскад конечно хорошо, и он сам создаст свои триггеры.
триггеры тоже хорошо, но позаписно - долго при массовом удалении, а на стейтмент - не очевидно, что вызовется каскадно, и дольше при удалении одной записи (а не массы).

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

для нерекурсиного скл по всем дочерним надо заранее позаботиться о его возможности - методов построения "нерекурсивного" дерева видимо не меньше 3-х. Но поддерживать все их надо триггерами либо хранимками.
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33690824
4321
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
J-Pro Имхо, триггер этого не сделает...неверно.
Вам достаточно в REFERENCE приписать ON DELETE CASCADE (сейчас у вас риференс ON DELETE RESTRICT - по умолчанию.)
И нужные (констрайнт)триггеры создадуться и сами все за вас сделают. Попробуйте и увидите все натурно.
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33690868
J-Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
4321каскад конечно хорошо, и он сам создаст свои триггеры.
триггеры тоже хорошо, но позаписно - долго при массовом удалении, а на стейтмент - не очевидно, что вызовется каскадно, и дольше при удалении одной записи (а не массы).

Прошу прощения за назойливость, но что такое "каскад"? :) Я понял, что Вы имеете в виду эту запись:

Код: plaintext
1.
2.
3.
...
child  int references tasks(id) on delete cascade
...

Но что она значит? В двух словах не могли бы пояснить? А доки я уже полистаю... Спасибо.


4321если предполагается частое массовое удаление - то лучче наверное хранимка, но не рекурсивная, которая удалит все дочернии махом.
Хмм... Странно, раньше терпеть не мог рекурсию, а сейчас не представляю как организовать "бесконечное" удаление "детей у детей" без рекурсии?


4321В рекурсивной же нет ничо проще, как не используя темповую просто делетить. (что у вас и написано с небольшими ошибками, и не понятно на что вам темповая табличка - видимо для каких -то иных нужд?).
Хм... Опять же странно, разве я написал с ошибками? Блин, ну почему Вы не указываете на них? :) А вообще, темповая таблица или рекорд нужны мне для того, чтобы запомнить всех детей перед тем, как я удалю связи. Ведь, связи между таблицами жесткие и я не удалю сначала таск из таблицы Tasks, а потом его связь TasksAssosiations. Мне надо сначала запомнить всех детей в эдакий массив, а потом по каждому ребёнку пройтись и проделать то же самое, понимаете? И вот как оное реализовать?


4321для нерекурсиного скл по всем дочерним надо заранее позаботиться о его возможности - методов построения "нерекурсивного" дерева видимо не меньше 3-х. Но поддерживать все их надо триггерами либо хранимками.

Не, наверное, лучше рекурсия... тока вот с темповыми таблицами разобраться... Подскажите, а?

Спасибо заранее!
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33690897
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
J-Proт.к. у таска 15 дети: 7,8,11, а у таска 7, в свою очередь, дети: 9, 10, 13. И их все рекурсивно надо удалить.вроде бы тут можно обойтись одной таблицей
Код: plaintext
1.
2.
3.
4.
5.
6.
create table t1 ( id serial primary key, name text, parent integer references t1(id) on delete cascade );
insert into t1 values (  1 , 'foo' );
insert into t1 values (  2 , 'bar',  1  );
insert into t1 values (  3 , 'baz',  2  );
select * from t1;
delete from t1 where id= 1 ;
select * from t1;
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33690905
J-Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
4321 J-Pro Имхо, триггер этого не сделает...неверно.
Вам достаточно в REFERENCE приписать ON DELETE CASCADE (сейчас у вас риференс ON DELETE RESTRICT - по умолчанию.)
И нужные (констрайнт)триггеры создадуться и сами все за вас сделают. Попробуйте и увидите все натурно.


Блин, так это то, что мне надо!

PostgreSQL helpCASCADE specifies that when a referenced row is deleted, row(s) referencing it should be automatically deleted as well.

А я, дурак, от незнания огороды городить начал... везде рестрикты ставил, блин...

НО, как я заметил, это пройдёт только для одного уровня. Удалять детей надо по-любому. А, чтобы их выбрать - нужна та же рекурсия... и временная таблица. Разве нет?

Ещё раз спасибо!
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33690928
J-Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
LeXa NalBat J-Proт.к. у таска 15 дети: 7,8,11, а у таска 7, в свою очередь, дети: 9, 10, 13. И их все рекурсивно надо удалить.вроде бы тут можно обойтись одной таблицей
Код: plaintext
1.
2.
create table t1 ( id serial primary key, name text, parent integer references t1(id) on delete cascade );
...


Спасибо. И обошёлся бы одной, да только один таск может иметь несколько детей, а так же один ребёнок сможет иметь несколько родителей. То бишь, многие-ко-многим, а оное реализуется лишь через связную таблицу... Вот.

Жду ответа на написанное мной двумя сообщениями ранее... Очень жду. Спасибо заранее!
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33690948
J-Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
J-ProНО, как я заметил, это пройдёт только для одного уровня. Удалять детей надо по-любому. А, чтобы их выбрать - нужна та же рекурсия... и временная таблица. Разве нет?

Всмысле, что опять же перед удалением таска надо удалить всех его детей и их детей и т.д. А их надо запомнить в какую-то запись и брать по одной. Рекурсией плюс временные таблицы не получится, по причине, описанной выше. А рекорд - не могу сделать SELECT как из таблицы, чтобы последний результат давал мне... Или можно, может, сделать тип set of records? :) Я действительно, ещё многого не знаю... Жду помощи...

Спасибо заранее!
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33691003
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
J-Proодин ребёнок сможет иметь несколько родителейудалять ребенка надо когда удалается единственный его родитель? то есть допустим у ребенка три родителя, удаляем одного родителя, затем удаляем другого, затем удаляем последнего и в этот момент должен удалиться ребенок, так?
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33691018
4321
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
J-Pro НО, как я заметил, это пройдёт только для одного уровня. Удалять детей надо по-любому. А, чтобы их выбрать - нужна та же рекурсия... и временная таблица. Разве нет?матьматьматьмать (по привыччке ответило экхо)

а папробовать? (чем чухню то пИсать). каскад срабатывает на каждую запиздь, т.е. в дите он тоже сработает - сл-но - отработает рекурсивно. единственный минус - массовые операции удаления в табличке начнут тормозить (о чем уже писалось).
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33691061
4321
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
J-Pro один ребёнок сможет иметь несколько родителей.это существенно. (т.е. просто каскадом тут не обойтись). каскад достаточен для удаления из таскс, из таска нужен триггер на Таскс примерно такой:

AS'
Удалить из ТАСК, где ТАСК.id = OLD.id И
не существует в ТАСКС где ТАСК.id = OLD.id
'
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33691073
J-Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
4321 J-Pro НО, как я заметил, это пройдёт только для одного уровня. Удалять детей надо по-любому. А, чтобы их выбрать - нужна та же рекурсия... и временная таблица. Разве нет?матьматьматьмать (по привыччке ответило экхо)

а папробовать? (чем чухню то пИсать). каскад срабатывает на каждую запиздь, т.е. в дите он тоже сработает - сл-но - отработает рекурсивно. единственный минус - массовые операции удаления в табличке начнут тормозить (о чем уже писалось).

Прежде чем отвечать сюда я всё попробовал. В вышеприведённом примере заменил RESTRICT на CASCADE и получил результат:

Таблица Tasks(пишу только ID): все, кроме 15 остались.
Таблица TasksAssosiations(пишу только ID): все связи остались, кроме связей, в которых учавствовал 15-й таск. Т.е. дети 15-го остались и связи их тоже.

А я хочу, чтобы было так:

Таблица Tasks(пишу только ID): 9 и 12.
Таблица TasksAssosiations(пишу только ID): TaskParentID = 9, TaskChildID = 12.

Так должно остаться, т.к. у таска 15 дети: 7,8,11, а у таска 7, в свою очередь, дети: 9, 10, 13. И их все рекурсивно надо удалить.


Так вот в хранимой процедуре DeleteTask я и хочу сделать рекурсивное удаление всех детей. За связи я уже не переживаю, т.к. вижу, что всех их удалит CASCADE. Но рекурсивно вызвать эту же хранимую процедуру для детей и прадетей таска 15 - мне просто необходимо. А чтобы это сделать, я должен узнать этих детей перед удалением 15-го таска(а, значит и всех его связей с детьми, раз стоит CASCADE). Понимаете?
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33691089
J-Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
LeXa NalBat J-Proодин ребёнок сможет иметь несколько родителейудалять ребенка надо когда удалается единственный его родитель? то есть допустим у ребенка три родителя, удаляем одного родителя, затем удаляем другого, затем удаляем последнего и в этот момент должен удалиться ребенок, так?

Гм... нет, честно говоря, этот момент я должен был проверить. Если больше одного родителя у ребёнка, то удаляем только родителя, ребёнка не трогаем, т.к. у него ещё есть родители. Но это легко проверить. Мне главное щас найти способ получения и чтения всех детей родителя... плюс рекурсия...
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33691099
4321
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
мои извинения. каскад отработал бы для дерева - когда 1 предок на потомка, и он (связз) сидит в _той же таблице_.

по поводу удаления детей - я выше привел логику триггера на удаление из таскс (удалять потомка при удалении последней связи). Может быть и другая логика - "удалять потомка при удалении любой связи", "делать потомка независимой задачей" и т.п.. Т.ч. вы оперделитесь :)
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33691101
J-Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
4321 J-Pro один ребёнок сможет иметь несколько родителей.это существенно. (т.е. просто каскадом тут не обойтись). каскад достаточен для удаления из таскс, из таска нужен триггер на Таскс примерно такой:

AS'
Удалить из ТАСК, где ТАСК.id = OLD.id И
не существует в ТАСКС где ТАСК.id = OLD.id
'

Это как раз для проверки на множество родителей, как я понял, да? Удалить только в том случае, если больше нет родителей. Но это же можно проверить и в хранимой процедуре, правильно?
В общем, на эту тему я подумаю отдельно, думаю, что тут проблем не возникнет. Что насчёт рекурсии и временной таблицы, уважаемый 4321? Вы поняли суть моего вопроса в предпоследнем ответе Вам?
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33691108
J-Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
4321мои извинения. каскад отработал бы для дерева - когда 1 предок на потомка, и он (связз) сидит в _той же таблице_.

по поводу удаления детей - я выше привел логику триггера на удаление из таскс (удалять потомка при удалении последней связи). Может быть и другая логика - "удалять потомка при удалении любой связи", "делать потомка независимой задачей" и т.п.. Т.ч. вы оперделитесь :)

Именно при удалении последнего потомка, Вы правы. Спасибо за триггер, я никогда их не писал, но смысл понял, попробую реализовать. Сейчас проблема не в этом... Думаю, теперь Вы понимаете, в чём? :)
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33691120
4321
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
для удаления потомка при удалении любого родителя см триггер от фффф
немного переделанный - ибо отрабатывает та таксксе
Код: plaintext
1.
2.
3.
4.
5.
CREATE OR REPLACE FUNCTION tr_tasksass_recursive_delete() RETURNS trigger LANGUAGE plpgsql AS $body$
BEGIN
  delete from task where id=OLD.parent;
  return OLD;
END;
$body$;
немного переписав получим для удаления по последнему
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
CREATE OR REPLACE FUNCTION tr_tasksass_recursive_delete() RETURNS trigger LANGUAGE plpgsql AS $body$
BEGIN
  delete from task 
     WHERE  id=OLD.parent
        AND NOT EXISTS(
        SELECT id FROM tasks s WHERE s.id = OLD.parent
         AND s.child<>OLD.childe);

  return OLD;
END;
$body$;
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33691131
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
J-ProГм... нет, честно говоря, этот момент я должен был проверить. Если больше одного родителя у ребёнка, то удаляем только родителя, ребёнка не трогаем, т.к. у него ещё есть родители. Но это легко проверить.да уж, специфицируйте пожалуйста задачу :)

J-ProМне главное щас найти способ получения и чтения всех детей родителя... плюс рекурсия...так все-таки что вам нужно, получить или удалить?

P.S.: кажется, что удаление можно сделать без самописных рекурсивных функций и временных таблиц примерно так, как написал фффф.
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33691163
4321
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
извините, фсё переврал (смешались в кучу кони, люди) - поправляюсь.
видимо так (логику уж проверьте сами):
4321для удаления потомка при удалении любого родителя см триггер от фффф
...
Код: plaintext
1.
2.
3.
4.
5.
CREATE OR REPLACE FUNCTION tr_tasksass_recursive_delete() RETURNS trigger LANGUAGE plpgsql AS $body$
BEGIN
  delete from task where id=OLD.childe;
  return OLD;
END;
$body$;
немного переписав получим для удаления по последнему
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
CREATE OR REPLACE FUNCTION tr_tasksass_recursive_delete() RETURNS trigger LANGUAGE plpgsql AS $body$
BEGIN
  delete from task 
     WHERE  id=OLD.childe
        AND NOT EXISTS(
        SELECT id FROM tasks s WHERE 
                         s.child=OLD.childe
                          AND s.parent<>OLD.parent );

  return OLD;
END;
$body$;
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33691393
J-Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
4321извините, фсё переврал (смешались в кучу кони, люди) - поправляюсь.
видимо так (логику уж проверьте сами):

....



Ничего, мне нужны все попытки помочь. Спасибо за то, что пытаетесь.

Теперь обьясню ситуацию: посмотрел доку по триггерам. Ничего сложного. Как я понял, фффф создаёт "поRECORDный" триггер, который выполняется уже ПОСЛЕ удаления. Отсюда первый вопрос: каскад уже сработает к моменту вызова триггера? Т.е. когда вызовется триггер, в таблице ассоциаций тасков уже не будет тех записей, в которых присутствовал удалённый таск? Иными словами, мы никак не узнаем информацию о детях и родителях этого удалённого таска?

Второй момент: писать триггер - всё равно, что писать хранимую процедуру. В том плане, что триггер нужен больше для того, если я работаю на уровне обычных SQL-запросов. Я же вызываю одни хранимые процедуры, у меня нет ни одного вызова простого запроса. А по сему, наверное, можно описать необходимые действия и в хранимой процедуре DeleteTask, ведь так? Это всё равно, что триггер, я могу делать в ней любые действия до того, как непосредственно вызову запрос: DELETE FROM Tasks. А сделать должен всё то же(используя вышеописанный код таблиц(где вместо RESTRICT стоит CASCADE) и предполагая, что удаляем таск 15, вызывая ф-цию DeleteTask(15)):

1. Удаляем всех детей.

выбираем из таблицы TasksAssosiations все ChildTaskID, у которых ParentTaskID = 15 и сохраняем куда-то в виде таблицы или массива ID. В данном случае это будет: 7, 8, 11. Это мы нашли детей 15-го таска.


в цикле, от 0 до 2 (или от 1 до 3) бежим по этим детям и вызываем для каждого рекурсивно эту же функцию, т.е. DeleteTask(7), DeleteTask(8), DeleteTask(11).

2. Удаляем сам таск 15, у которого больше нет детей, но, возможно есть родители, которых не нужно трогать, просто оставив их без связи с удалённым 15-м (как? см. ниже)


после выхода из цикла можем окончательно удалить таск 15. При этом удалении из таблицы TaskAssosiations, благодаря CASCADE, автоматически удалятся все связи таска 15 с возможными его родителями БЕЗ удаления последних. Что мне и надо.


Так проблема яснее, народ? Алгоритм налицо. Теперь вернусь к первоначальному вопросу: какой тип данных мне использовать для хранения и извлечения детей удаляемого таска (первый подпункт первого пункта)?

Спасибо вам всем заранее.
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33691578
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
J-Pro1. Удаляем всех детей.

выбираем из таблицы TasksAssosiations все ChildTaskID, у которых ParentTaskID = 15 и сохраняем куда-то в виде таблицы или массива ID. В данном случае это будет: 7, 8, 11. Это мы нашли детей 15-го таска.


в цикле, от 0 до 2 (или от 1 до 3) бежим по этим детям и вызываем для каждого рекурсивно эту же функцию, т.е. DeleteTask(7), DeleteTask(8), DeleteTask(11).

Теперь вернусь к первоначальному вопросу: какой тип данных мне использовать для хранения и извлечения детей удаляемого таска (первый подпункт первого пункта)?
Код: plaintext
1.
2.
FOR child IN select * from TasksAssosiations where ParentTaskID =  15  LOOP
  select DeleteTask(child.ChildTaskID);
END LOOP;
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33691591
J-Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Подумал над последствиями CASCADE и надумал вот такой вариант:

Код: 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.
26.
27.
28.
29.
30.
31.
CREATE OR REPLACE FUNCTION "public"."DeleteTask" (taskid integer) RETURNS bit AS
$body$
DECLARE ID1 INTEGER;
DECLARE quan INTEGER;

BEGIN

-- узнаём кол-во детей данного таска
SELECT INTO quan count(*) FROM "TasksAssociations" WHERE "ParentTaskID" = taskid;

-- пока дети есть в таблице ассоциаций
WHILE (quan !=  0 )
LOOP
 -- выбираем одного ребёнка в переменную
 SELECT INTO ID1 "ChildTaskID" FROM "TasksAssociations" WHERE "ParentTaskID" = taskid;
 -- удаляем ребёнка (CASCADE удалит и ео связи со всеми из таблицы TasksAssosiations)
 PERFORM * FROM public."DeleteTask"(ID1);
 -- узнаём новое кол-во детей у заданного таска
 SELECT INTO quan count(*) FROM "TasksAssociations" WHERE "ParentTaskID" = taskid;

END LOOP;

-- удаляем заданный таск, который уже без детей
DELETE FROM "Tasks"
WHERE "TaskID" = taskid;

RETURN  1 ;

END;
$body$
LANGUAGE 'plpgsql' VOLATILE CALLED ON NULL INPUT SECURITY INVOKER;


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

А больше никто ничего не может предложить, народ?
...
Рейтинг: 0 / 0
Рекурсия + временные таблицы
    #33691630
J-Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
LeXa NalBat
Код: plaintext
1.
2.
FOR child IN select * from TasksAssosiations where ParentTaskID =  15  LOOP
  select DeleteTask(child.ChildTaskID);
END LOOP;


Согласен, так же, как у меня, только намного рациональнее. Но результат тот же самый - дебагером всё проходит отлично, из цикла выходит, но ни одной записи из таблиц не удаляется.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
CREATE OR REPLACE FUNCTION "public"."DeleteTask" (taskid integer) RETURNS bit AS
$body$

DECLARE rec RECORD;

BEGIN


FOR rec IN select * from "TasksAssociations" where "ParentTaskID" = taskid
LOOP
  perform "public"."DeleteTask"(rec."ChildTaskID");
END LOOP;


DELETE FROM "Tasks"
WHERE "TaskID" = taskid;

RETURN  1 ;

END;
$body$
LANGUAGE 'plpgsql' VOLATILE CALLED ON NULL INPUT SECURITY INVOKER;
...
Рейтинг: 0 / 0
25 сообщений из 30, страница 1 из 2
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Рекурсия + временные таблицы
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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