PostgreSQL «Отложенное удаление» все еще накладывает ограничение на удаление - PullRequest
5 голосов
/ 19 июля 2010

Я хочу удалить строки из двух таблиц, которые зависят друг от друга с помощью набора отложенных ограничений. Чтобы упростить этот пост, я смоделировал простую схему БД.

Я надеюсь удалить записи из некоторой таблицы 'delete_from_me' внутри транзакции SQL / DB Patch. Уловка в том, что я хочу удалить на основе выбора из второй таблицы 'constraining_table', прежде чем потерять саму ссылку.

Вот описание двух таблиц:

tab-quarantine=> \d delete_from_me
       Table "public.delete_from_me"
  Column   |       Type        | Modifiers 
-----------+-------------------+-----------
 id        | character varying | not null
 extension | character varying | not null
Indexes:
    "delete_from_me_pkey" PRIMARY KEY, btree (id)

tab-quarantine=> \d constraining_table 
   Table "public.constraining_table"
 Column |       Type        | Modifiers 
--------+-------------------+-----------
 image  | character varying | not null
 type   | character varying | not null
Foreign-key constraints:
    "constraining_table_image_fkey" FOREIGN KEY (image) REFERENCES delete_from_me(id)
         ON UPDATE CASCADE
         ON DELETE RESTRICT DEFERRABLE

Вот некоторые примеры данных, которые я только что там написал:

tab-quarantine=> SELECT * FROM delete_from_me;
     id     | extension 
------------+-----------
 12345abcde | png
(1 row)

tab-quarantine=> SELECT * FROM constraining_table;
   image    |   type   
------------+----------
 12345abcde | select_me
(1 row)

И вот моя транзакция:

BEGIN;
\set ON_ERROR_STOP 1
SET CONSTRAINTS ALL DEFERRED;
DELETE FROM delete_from_me WHERE id IN (
    SELECT image FROM constraining_table WHERE type = 'select_me'
);
DELETE FROM constraining_table WHERE type = 'select_me';
COMMIT;

Эта транзакция не выполнена. Когда я перехожу и делаю это вручную, мне выдается следующее сообщение об ошибке:

ERROR:  update or delete on table "delete_from_me" violates foreign key constraint "constraining_table_image_fkey" on table "constraining_table"
DETAIL:  Key (id)=(12345abcde) is still referenced from table "constraining_table".

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

1 Ответ

6 голосов
/ 19 июля 2010

Используйте ON DELETE NO ACTION DEFERRABLE вместо ON DELETE RESTRICT DEFERRABLE. Использование RESTRICT вместо NO ACTION заставляет ограничение не переноситься, независимо от того, применяется ли модификатор DEFERRABLE.

Это мелкий шрифт справочной страницы для CREATE TABLE:

Ссылочные действия, кроме проверки NO ACTION, не могут быть отложены, даже если ограничение объявлено отложенным.

Очевидно, что вышеупомянутая оговорка включает в себя RESTRICT.

Вскоре после этого предложения приводятся определения NO ACTION и RESTRICT:

НЕТ ДЕЙСТВИЙ

Создает ошибку, указывающую, что удаление или обновление приведет к нарушению ограничения внешнего ключа. Если ограничение откладывается, эта ошибка будет возникать во время проверки ограничения, если все еще существуют какие-либо ссылочные строки. Это действие по умолчанию.

RESTRICT

Создать ошибку, указывающую, что удаление или обновление приведет к нарушению ограничения внешнего ключа. Это то же самое, что НЕТ ДЕЙСТВИЯ, за исключением того, что проверка не откладывается.

Как видите, NO ACTION будет вести себя идентично RESTRICT, за исключением того, что NO ACTION является отложенным. Вот почему я рекомендовал это - я думаю, что это именно то, что вы просите.

...