PostgreSQL Каскад для столбцов (не внешний ключ) - PullRequest
0 голосов
/ 16 марта 2020
create table parent (
    child_type not null  
    child_id not null
);
create table child1(id not null);
create table child2(id not null);
create table child3(id not null);

И есть несколько строк в родительской таблице, например:

child_type,child_id
"child1",1
"child1",2
"child2",1
"child3",1

Я хочу удалить дочернюю строку при удалении родительской строки. Есть ли способ сделать этот триггер на каскад удаления?

Ответы [ 2 ]

0 голосов
/ 16 марта 2020

Я надеюсь, что это сложная ситуация для вас, настоящая проблема, так как это действительно ужасный дизайн. Предполагая, что вы на самом деле "хотите удалить дочернюю строку, когда я удаляю родительскую строку" . Если вы не измените свою модель данных и не определите ограничения FK, вам потребуется триггер удаления родительского элемента таблицы. Вы НЕ МОЖЕТЕ каскадно удалять без FK, поскольку именно здесь вы определяете Postgres. Кстати, ваши определения таблиц недействительны. Not Null - это ограничение, а не тип данных, вы не установили тип данных. После исправления вы можете создать триггер, который удалит соответствующие строки из соответствующей дочерней таблицы, если ваш столбец child_type понимает имя таблицы, в которой находится дочерний элемент. Очень плохой дизайн, приводящий к крайне рискованному предположению, но:

-- setup

    create table parent (
        child_type text    not null  
       ,child_id   integer not null
    );
    create table child1(id integer not null);
    create table child2(id integer not null);
    create table child3(id integer not null)

    insert into parent(child_type, child_id) 
      values ('child1',1),('child1',2),('child2',1),('child3',1);

    insert into child1(id) values (1),(2);
    insert into child2(id) values (1);
    insert into child3(id) values (1);

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

-- build trigger function.
create or replace function parent_adr()
returns trigger 
language plpgsql
as $$
declare 
   base_del_lk constant text = 'delete from %s where id = %s'; 
   sql_delete_stmt_l text; 
begin
   sql_delete_stmt_l = format(base_del_lk,old.child_type, old.child_id);
   raise notice 'Running statement==%', sql_delete_stmt_l;
   EXECUTE  sql_delete_stmt_l;
   return old;
end; 
$$;

-- and define the trigger on the parent table.  
create trigger parent_adr_trig
    after delete
    on parent
    for each row
    execute procedure parent_adr(); 



--- test.     
delete from parent where child_type = 'child1';
0 голосов
/ 16 марта 2020

Я предполагаю, что (child_type,child_id) является первичным ключом parent (и этот совет будет работать только в том случае, если он таков: если вы хотите удалить родительскую строку, чтобы инициировать удаление в дочернем элементе через каскад FK, у родителя должен быть первичный ключ)

Вы создаете ассоциации следующим образом:

create table child1(
  child_type VARCHAR(20) DEFAULT 'child1', 
  id INT not null
  FOREIGN KEY (child_type,id) REFERENCES parent(child_type, child_id) ON DELETE CASCADE
);
create table child2(
  child_type VARCHAR(20) DEFAULT 'child2', 
  id INT not null
  FOREIGN KEY (child_type,id) REFERENCES parent(child_type, child_id) ON DELETE CASCADE
);
create table child3(
  child_type VARCHAR(20) DEFAULT 'child3', 
  id INT not null
  FOREIGN KEY (child_type,id) REFERENCES parent(child_type, child_id) ON DELETE CASCADE
);

Вы не можете иметь только id в дочерних ссылках части составного PK в родительском элементе; У child должен быть тот же N столбцов с теми же значениями, что и у родительского PK


ПОЭТОМУ, что структура таблицы действительно изящна, и, вероятно, она снова и снова будет кусать вас.

Предпочитаю что-то более нормальное, например:

create table parent (
    id PRIMARY KEY
);
create table child1(id PRIMARY KEY, parent_id REFERENCES parent(id));
create table child2(id PRIMARY KEY, parent_id REFERENCES parent(id));
create table child3(id PRIMARY KEY, parent_id REFERENCES parent(id));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...