Сбой удаления PostgreSQL с правилом ON DELETE для унаследованной таблицы - PullRequest
1 голос
/ 28 сентября 2011

В моей базе данных PostgreSQL 9.1 я определил ПРАВИЛА, которые удаляют строки из дочерних таблиц всякий раз, когда удаляется строка родительской таблицы.Все это работало нормально, пока я не ввел наследство.Если родительская (ссылающаяся) таблица INHERITS из другой таблицы и я удаляю ее из базовой таблицы, то УДАЛЕНИЕ выполняется успешно, но ПРАВИЛО вообще не срабатывает - указанная строка не удаляется.Если я пытаюсь удалить из производной таблицы, я получаю сообщение об ошибке:

update or delete on table "referenced" violates foreign key constraint "fk_derived_referenced" on table "derived"

В родительской таблице нет другой строки, которая нарушала бы внешний ключ: на нее ссылается удаляемая строка!Как это исправить?

Следующий скрипт воспроизводит проблему:

-- Schema

CREATE TABLE base
(
  id serial NOT NULL,
  name character varying(100),
  CONSTRAINT pk_base PRIMARY KEY (id)
);

CREATE TABLE referenced
(
  id serial NOT NULL,
  value character varying(100),
  CONSTRAINT pk_referenced PRIMARY KEY (id)
);

CREATE TABLE derived
(
  referenced_id integer,
  CONSTRAINT pk_derived PRIMARY KEY (id),
  CONSTRAINT fk_derived_referenced FOREIGN KEY (referenced_id) REFERENCES referenced (id)
)
INHERITS (base);

-- The rule

CREATE OR REPLACE RULE rl_derived_delete_referenced
AS ON DELETE TO derived DO ALSO
DELETE FROM referenced r WHERE r.id = old.referenced_id;

-- Some test data

INSERT INTO referenced (id, value)
VALUES (1, 'referenced 1');

INSERT INTO derived (id, name, referenced_id)
VALUES (2, 'derived 2', 1);

-- Delete from base - deletes the "base" and "derived" rows, but not "referenced"
--DELETE FROM base
--WHERE id = 2;

-- Delete from derived - fails with:
-- update or delete on table "referenced" violates foreign key constraint "fk_derived_referenced" on table "derived"
DELETE FROM derived
WHERE id = 2

Ответы [ 2 ]

1 голос
/ 28 сентября 2011

Как я сказал в своем комментарии, это кажется необычным способом сделать что-то. Но вы можете заставить его работать с отложенным ограничением.

CREATE TABLE derived
(
  referenced_id integer,
  CONSTRAINT pk_derived PRIMARY KEY (id),
  CONSTRAINT fk_derived_referenced FOREIGN KEY (referenced_id) 
    REFERENCES referenced (id) DEFERRABLE INITIALLY DEFERRED
)
INHERITS (base);

Документы PostgreSQL, Правила и триггеры , скажем

Многие вещи, которые можно сделать с помощью триггеров, также могут быть реализованы. используя систему правил PostgreSQL. Одна из вещей, которые не могут быть В соответствии с правилами, некоторые виды ограничений, особенно иностранных ключи.

Но мне не ясно, с каким именно ограничением вы сталкиваетесь.

0 голосов
/ 28 сентября 2011

Кроме того, вам нужно проверить, все ли другие записи все еще ссылаются на строки, которые будут удалены.Я добавил тестовую запись № 3, которая указывает на ту же самую справочную запись № 1.

-- The rule    
CREATE OR REPLACE RULE rl_derived_delete_referenced
AS ON DELETE TO tmp.derived DO ALSO (
    DELETE FROM tmp.referenced re_del
    WHERE re_del.id = OLD.referenced_id
    AND NOT EXISTS ( SELECT * FROM tmp.derived other
        WHERE other.referenced_id = re_del.id
        AND other.id <> OLD.id )
        ;
    );

-- Some test data

INSERT INTO tmp.referenced (id, value)
VALUES (1, 'referenced 1');

-- EXPLAIN ANALYZE
INSERT INTO tmp.derived (id, name, referenced_id)
VALUES (2, 'derived 2', 1); 

INSERT INTO tmp.derived (id, name, referenced_id)
VALUES (3, 'derived 3', 1);

-- Delete from base - deletes the "base" and "derived" rows, but not "referenced"
--DELETE FROM base
--WHERE id = 2;

-- Delete from derived - fails with:
-- update or delete on table "referenced" violates foreign key constraint "fk_derived_referenced" on table "derived"

EXPLAIN ANALYZE
DELETE FROM tmp.derived
WHERE id = 2
    ;

SELECT * FROM tmp.base;
SELECT * FROM tmp.derived;
SELECT * FROM tmp.referenced;
...