У меня есть база данных Postgresql, в которой я хочу сделать несколько каскадных удалений. Однако таблицы не настраиваются с правилом ON DELETE CASCADE. Есть ли способ, которым я могу выполнить удаление и сказать Postgresql каскадировать это только один раз? Что-то эквивалентное
DELETE FROM some_table CASCADE;
Ответы на этот старый вопрос создают впечатление, что такого решения не существует, но я решил, что задам этот вопрос явно, просто чтобы быть уверенным.
postgresql
Эли Кортрайт
источник
источник
Ответы:
Нет. Чтобы сделать это только один раз, вы просто напишите оператор удаления для таблицы, которую вы хотите каскадировать.
источник
Если вы действительно хотите,
DELETE FROM some_table CASCADE;
что означает « удалить все строки из таблицыsome_table
», вы можете использоватьTRUNCATE
вместоDELETE
иCASCADE
всегда поддерживается. Однако, если вы хотите использовать выборочное удаление сwhere
предложением,TRUNCATE
этого недостаточно.ИСПОЛЬЗОВАТЬ С УХОДОМ - Это удалит все строки всех таблиц, для которых есть ограничение внешнего ключа,
some_table
и всех таблиц, которые имеют ограничения для этих таблиц и т. Д.Postgres поддерживает
CASCADE
с командой TRUNCATE :Удобно, что это транзакционный (то есть может быть откат), хотя он не полностью изолирован от других одновременных транзакций и имеет несколько других предостережений. Прочитайте документы для деталей.
источник
Я написал (рекурсивную) функцию для удаления любой строки на основе ее первичного ключа. Я написал это, потому что я не хотел создавать свои ограничения как «на каскаде удаления». Я хотел иметь возможность удалять сложные наборы данных (в качестве администратора баз данных), но не позволять моим программистам иметь возможность каскадного удаления, не продумывая все последствия. Я все еще тестирую эту функцию, поэтому в ней могут быть ошибки - но, пожалуйста, не пытайтесь ее использовать, если ваша БД имеет многоколонные первичные (и, следовательно, внешние) ключи. Кроме того, все ключи должны быть представлены в виде строки, но они могут быть написаны так, чтобы не иметь этого ограничения. В любом случае, я использую эту функцию ОЧЕНЬ ИСКЛЮЧИТЕЛЬНО, я слишком дорожу своими данными, чтобы включить каскадные ограничения для всего. В основном эта функция передается в схеме, имени таблицы и первичном значении (в виде строки), и он начнет с поиска любых внешних ключей в этой таблице и удостоверится, что данные не существуют - если это произойдет, он рекурсивно вызывает себя для найденных данных. Он использует массив данных, уже помеченных для удаления, чтобы предотвратить бесконечные циклы. Пожалуйста, проверьте это и дайте мне знать, как это работает для вас. Примечание: это немного медленно. Я называю это так:
select delete_cascade('public','my_table','1');
источник
IN
оператор с вложенными выборками вместо=
(так что шаг для использования логики множеств), это стало бы намного быстрее.Если я правильно понимаю, вы сможете делать то, что хотите, отменив ограничение внешнего ключа, добавив новое (которое будет каскадно), выполнив свои действия и воссоздав ограничивающее ограничение внешнего ключа.
Например:
Конечно, вы должны абстрагировать подобные вещи в процедуру, ради вашего психического здоровья.
источник
Я не могу комментировать ответ Палехорса, поэтому я добавил свой собственный ответ. Логика Палехорса в порядке, но эффективность может быть плохой с большими наборами данных.
Это быстрее, если у вас есть индексы для столбцов и набор данных больше, чем несколько записей.
источник
Да, как уже говорили другие, нет удобного «УДАЛИТЬ ИЗ my_table ... CASCADE» (или эквивалент). Чтобы удалить не каскадные дочерние записи, защищенные внешним ключом, и их предков, на которые ссылаются, вы можете выбрать следующие параметры:
Я предполагаю, что намеренно обходить ограничения внешнего ключа не удобно; но я понимаю, почему в определенных обстоятельствах вы захотите это сделать. Если это то, чем вы будете заниматься с какой-то частотой, и если вы хотите повсюду пренебрегать мудростью администраторов баз данных, вы можете автоматизировать это с помощью процедуры.
Я приехал сюда несколько месяцев назад в поисках ответа на вопрос «УДАЛИТЬ КАСКАД только один раз» (первоначально задавался более десяти лет назад!). Я получил некоторое преимущество от умного решения Джо Лава (и варианта Томаса К.Г. де Вильены), но, в конце концов, в моем случае использования были особые требования (например, обработка циклических ссылок внутри таблицы), что заставило меня выбрать другой подход. Этот подход в конечном итоге стал recursively_delete (PG 10.10).
Я уже некоторое время использую recursively_delete в производстве и, наконец, чувствую себя (достаточно осторожно) достаточно уверенно, чтобы сделать его доступным для других, которые могут оказаться здесь в поисках идей. Как и в случае решения Joe Love, оно позволяет вам удалять целые графы данных, как если бы все ограничения внешнего ключа в вашей базе данных были на мгновение установлены на CASCADE, но предлагает пару дополнительных функций:
источник
Вы можете использовать для автоматизации этого, вы можете определить ограничение внешнего ключа с помощью
ON DELETE CASCADE
.Я цитирую руководство по ограничениям внешнего ключа :
источник
Я взял ответ Джо Лав и переписал его, используя
IN
оператор с подвыборками вместо того,=
чтобы сделать функцию быстрее (согласно предложению Hubbitus):источник
in
оператора и подзапросов.Удаление с опцией каскада применяется только к таблицам с определенными внешними ключами. Если вы делаете удаление, и он говорит, что вы не можете, потому что это нарушило бы ограничение внешнего ключа, каскад заставит его удалить ошибочные строки.
Если вы хотите удалить связанные строки таким способом, вам нужно сначала определить внешние ключи. Кроме того, помните, что если вы явно не дадите ему указание начать транзакцию или не измените значения по умолчанию, он выполнит автоматическую фиксацию, которая может занять очень много времени для очистки.
источник