Видаліть рядки із зовнішнім ключем у PostgreSQL


84

Я хотів би видалити рядки, які містять зовнішній ключ, але коли я намагаюся щось подібне:

DELETE FROM osoby WHERE id_osoby='1'

Я отримую таке твердження:

ПОМИЛКА: оновлення або видалення в таблиці "osoby" порушує обмеження зовнішнього ключа "kontakty_ibfk_1" в таблиці "kontakty" ДЕТАЛЬНО: Ключ (id_osoby) = (1) все ще посилається на таблицю "kontakty".

Як я можу видалити ці рядки?


3
Перевірте це також на видаленні каскадів ;) Хороше, щоб ці налаштування були у вашій таблиці .. Коли creating foreign keysми add parent then child. Тож при видаленні we delete child and then parent;)
bonCodigo

Відповіді:


95

Щоб автоматизувати це, ви можете визначити обмеження зовнішнього ключа за допомогою ON DELETE CASCADE.
Я цитую посібник з обмежень зовнішнього ключа :

CASCADE визначає, що коли рядок, на який посилається, видаляється, рядки, що посилаються на нього, також повинні бути автоматично видалені.

Подивіться на поточне визначення FK наступним чином:

SELECT pg_get_constraintdef(oid) AS constraint_def
FROM   pg_constraint
WHERE  conrelid = 'public.kontakty'::regclass  -- assuming pubic schema
AND    conname = 'kontakty_ibfk_1';

Потім додайте або модифікуйте ON DELETE ...деталь до ON DELETE CASCADE(зберігаючи все інше як є) у твердженні типу:

ALTER TABLE kontakty
   DROP CONSTRAINT kontakty_ibfk_1
 , ADD  CONSTRAINT kontakty_ibfk_1
   FOREIGN KEY (id_osoby) REFERENCES osoby (id_osoby) ON DELETE CASCADE;

Оскільки ALTER CONSTRAINTсинтаксису немає , скиньте та відтворіть обмеження в одному ALTER TABLEвисловлюванні. Це дозволяє уникнути можливих перегонових умов із одночасним доступом до запису.

Для цього вам потрібні привілеї, очевидно. Операція бере ACCESS EXCLUSIVEзамок на столі kontaktyі SHARE ROW EXCLUSIVEзамок на столі osoby.

Якщо ALTERтаблиці не вдається , видалення вручну (один раз) або тригер BEFORE DELETE(кожен раз) - це інші варіанти.


4
У нас не створено таблиць з ON DELETE CASCADE. Я не можу змінити структуру таблиць. Чи існує спосіб автоматичного видалення зовнішніх ключів? або ми повинні йти шляхом, запропонованим @juergen d
वरुण

2
@Varun: Якщо вам не вдається ALTERтаблиця, з якою можна додати ФК ON DELETE CASCADE, тоді видалення вручну (один раз) або тригер BEFORE DELETE(кожен раз) - це інші варіанти.
Ервін Брандштеттер

Класно, тому відповідь полягає у додаванні ON DELETE CASCADEдо стовпця із зовнішнім ключем у вашій заяві create.
425несп

1
@ 425nesp: Я додав чіткі інструкції.
Ервін

У моєму випадку мені знадобився DDL, щоб побачити точне обмеження імені, в цьому випадку це буде\d kontakty
marquicus

36

Ви не можете видалити зовнішній ключ, якщо він все ще посилається на іншу таблицю. Спочатку видаліть посилання

delete from kontakty
where id_osoby = 1;

DELETE FROM osoby 
WHERE id_osoby = 1;

31

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

У моєму випадку я перебуваю в режимі розробки і маю кілька таблиць, які посилаються одна на одну за допомогою зовнішніх ключів. Таким чином, видалити їх вміст не так просто, як видалити всі рядки з однієї таблиці перед іншою. Отже, для мене вдало видалити їхній вміст наступним чином:

ALTER TABLE table1 DISABLE TRIGGER ALL;
ALTER TABLE table2 DISABLE TRIGGER ALL;
DELETE FROM table1;
DELETE FROM table2;
ALTER TABLE table1 ENABLE TRIGGER ALL;
ALTER TABLE table2 ENABLE TRIGGER ALL;

Ви повинні мати можливість додавати пропозиції WHERE за бажанням, звичайно, обережно, щоб уникнути підриву цілісності бази даних.

Існує кілька хороших, пов’язаних дискусій на http://www.openscope.net/2012/08/23/subverting-foreign-key-constraints-in-postgres-or-mysql/


Архівна версія мертвого посилання: web.archive.org/web/20160922175428/http://www.openscope.net/… . (запропонована черга редагування заповнена, тому у мене недостатньо представників, щоб редагувати її самостійно)
Йоакім

22

Минув деякий час з того часу, як було поставлено це питання, надія може допомогти. Оскільки ви не можете змінити або змінити структуру db, ви можете це зробити. відповідно до postgresql docs .

TRUNCATE - спорожнення таблиці або набору таблиць.

TRUNCATE [ TABLE ] [ ONLY ] name [ * ] [, ... ]
    [ RESTART IDENTITY | CONTINUE IDENTITY ] [ CASCADE | RESTRICT ]

Опис

TRUNCATE швидко видаляє всі рядки з набору таблиць. Це має такий самий ефект, як некваліфіковане ВИДАЛЕННЯ для кожної таблиці, але оскільки воно насправді не сканує таблиці, це швидше. Крім того, він відновлює дисковий простір негайно, а не вимагає подальшої операції VACUUM. Це найкорисніше на великих столах.


Зрізати таблицю othertable та каскадувати до будь-яких таблиць, які посилаються на othertable через обмеження зовнішнього ключа:

TRUNCATE othertable CASCADE;

Те саме, а також скинути будь-які пов'язані генератори послідовностей:

TRUNCATE bigtable, fattable RESTART IDENTITY;

Зрізання та скидання будь-яких пов'язаних генераторів послідовностей:

TRUNCATE revinfo RESTART IDENTITY CASCADE ;

1
Хороший, дуже корисний.
Sethaft

5

Це означає, що в таблиці у kontaktyвас є рядок, що посилається на рядок, який osobyви хочете видалити. Ви повинні спочатку видалити цей рядок або встановити каскадне видалення відношення між таблицями.

Поводзеня!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.