[postgres] Как сделать что-то вроде DELETE ... CASCADE?

kruzer25

Ситуация - имеется таблица, на неё ссылаются другие таблицы (конечно, с on delete restrict на те таблицы ссылаются ещё какие-то (с on delete restrict и так далее. Это правильно, там действительно должен быть on delete restrict, в обычной жизни всё так и должно быть.
Теперь вдруг мне становится очень нужно удалить ряд из первой таблицы. Это администрирование системы, всё делается руками, тот, кто это делает - знает, что он делает, про foreign keys он в курсе, он просто хочет, чтобы всё каскадно удалилось. Но у delete нет никаких опций, а если запускать его просто так - конечно же, вываливается что-нибудь вроде:
ERROR:  update or delete on table "Accounts" violates foreign key constraint "AccountingBills_AccountId_fkey" on table "AccountingBills"
DETAIL: Key (Id)=(2) is still referenced from table "AccountingBills".

Да, я знаю, что какие-то записи в других таблицах ссылаются на эту, я просто хочу сделать каскадное удаление.
В интернете смог нарыть несколько обсуждений этого вопроса, везде советуют человеку сначала удалять записи в таблицах со ссылками, или удалить foreign key, создать новый с on delete cascade, сделать то что надо, удалить новый foreign key, создать старый с on delete restrict. Это, конечно, всё очень хорошо, когда у нас только две таблицы с десятком записей в каждой; но когда этих таблиц под сотню, а ряд я хочу удалить из настолько основной таблицы, что чуть ли не все остальные ссылаются на неё прямо или через одну-две-три другие таблицы, и в каждой таблице может быть по дохрена записей (так, что новые foreign keys будут считаться офигенно долго) - это, конечно, не вариант; придётся целый день потратить, составляя все эти запросы для каждой таблицы, и всё равно где-нибудь ошибёшься.
Поэтому - вопрос. Можно ли как-нибудь осуществить каскадное удаление в постгресе?
Единственное, что пока что пришло в голову - парсить процитированное здесь сообщение об ошибке, после чего писать новый запрос, удаляющий соответствующие записи (всё это делается автоматически). Но это, конечно, изврат.

katrin2201

Единственное, что пока что пришло в голову - парсить процитированное здесь сообщение об ошибке, после чего писать новый запрос, удаляющий соответствующие записи (всё это делается автоматически). Но это, конечно, изврат.
Построить граф зависимостей по information_schema, и удалять руководствуясь им.

kruzer25

То есть, по сути, делать всё это руками (или писать скрипт для автоматизации) - как и с вариантом в конце моего поста.
Странно, что база данных не предоставляет такую возможность.

livemix

Предоставляет. Для этого надо не restrict правила задавать, а cascade - тогда будет возможность.

kruzer25

Повторяю для тех, кто не прочитал первый пост.
Правила уже есть. При обычной работе эти правила должны соблюдаться.
Что ты предлагаешь? Вернуться на три года назад в прошлое, к моменту первичной разработки структуры базы, и сделать вместо restrict - cascade, потому что вдруг мы когда-нибудь что-нибудь захотим, а до тех пор пусть всё работает криво? Или переделать сейчас все правила во всех таблицах с restrict на cascade, а потом вернуть назад? Или что?
Я хочу удалить записи из настолько ключевой таблицы, что непосредственно на неё ссылаются 83 другие таблицы. А ещё некоторое количество таблиц ссылается на эти "другие"; да и сами эти 83 ссылаются друг на друга, так что в каком-то порядке удалять нельзя. В этих таблицах уже есть дохрена данных.
Что, по мнению разработчиков постгреса, мне надо делать в такой ситуации? Удалить все старые правила (потому что если и есть некоторые правила, которые не связаны с тем деревом, которое растёт из нужной таблицы - никто высчитывать это сейчас не будет делать новые, удалить нужную строку, удалить новые правила, создать старые? Всё - с соответствующими тормозами? С учётом того, что, пока мы там возимся со всей этой хренью - все таблицы во всей базе залочены, и никто ничего больше не может в это время делать? Это уж как-то совсем через жопу.
Поэтому остаётся только изобретать велосипед - писать скрипт, который строит граф зависимостей, и сам в нужном порядке удаляет нужные записи. По сути, реализовывать то, что почему-то не реализовали разработчики постгреса. Каскадное удаление в постгресе есть, но до него не добраться, потому что кто-то решил, что раз on delete restrict - так значит никому и никогда, даже администратору базы, не может понадобиться такое удаление. Поэтому пишем ещё одно каскадное удаление в своей системе, замечательное решение.

Dasar

> Что ты предлагаешь?
признать, что у тебя есть противоречивые желания: хочу что бы был restrict, но иногда cascade
признать, что текущее решение (и используемые в нем инструмены: postgress и т.д.) было построено/выбрано без учета этого желания.
признать, что при выше приведенных условиях - искомый выход будет кривым и требовать много работы.
признать, что перекладывание ответственности за свои желания на других (а тем более на инструменты) не достойно для человека (а уж тем более для мужчины а значит надо стиснут зубы и реализовать то геморройное решение которое есть

kruzer25

хочу что бы был restrict, но иногда cascade
Да. Только не просто "иногда", а в исключительных ситуациях, при ручном администрировании этой базы. За три года такое желание возникло в первый раз; крайне сомнительно, что оно возникнет ещё когда-нибудь.
текущее решение (и используемые в нем инструмены: postgress и т.д.) было построено/выбрано без учета этого желания.
Да.
перекладывание ответственности за свои желания на других (а тем более на инструменты) не достойно для человека
Тем не менее, по-моему, разработчики постгреса поступили очень нехорошо, не оставив никакой возможности воспользоваться уже имеющейся функциональностью при on delete cascade. В результате, приходится писать свой велосипед, потому что разработчики решили, что, если база в самом начале была настроена каким-то образом - к имеющемуся велосипеду нельзя подпускать даже администратора при ручной работе с базой.
Я не вижу ни одной причины (кроме того, что пришлось бы потратить некоторое небольшое время на реализацию этого по которой не сделали специальную возможность удаления cascade, когда в настройках ключа не сказано cascade.
Поэтому - реализуем велосипед, и провоцируем других разработчиков на использование каскадного удаления уже без такого повода, который есть в данном случае - потому что велосипед будет гораздо доступнее, чем был бы специальный запрос. По-моему, такая "защита от дурака" не имеет никакого смысла - всё равно, что файрвол, который не умеет открывать отдельные порты, а работает только в режиме "закрыто всё". Это, конечно, непробиваемая защита, но все пользователи первым делом будут отключать его, и от защиты не останется ничего.

katrin2201

Тем не менее, по-моему, разработчики постгреса поступили очень нехорошо, не оставив никакой возможности воспользоваться уже имеющейся функциональностью при on delete cascade
Так поступили разработчики большинства (если не всех) rdbms
Да и в конце концов, написать нужную тебе тулзёвину - дело нескольких часов.

Dasar

Тем не менее, по-моему, разработчики постгреса поступили очень нехорошо, не оставив никакой возможности воспользоваться уже имеющейся функциональностью при on delete cascade.
ты хочешь открытое гибкое решение, но открытое гибкое решение - тяжело реализовывается.
Ты уже заплатил разработчикам postgress за такую тяжелую сложную реализацию гибкого открытого решения?

kruzer25

Да и в конце концов, написать нужную тебе тулзёвину - дело нескольких часов.
Знаешь, очень неприятно потратить несколько часов (у меня это получилось ближе к полному рабочему дню) на то, что можно было бы сделать одним запросом за пять минут. Особенно, когда это вообще довольно побочная вещь.

kruzer25

ты хочешь открытое гибкое решение, но открытое гибкое решение - тяжело реализовывается.
У меня ушёл рабочий день на то, чтобы написать этот велосипед. У них этот велосипед уже есть, просто спрятан. Наверное, не так уж тяжело было бы это реализовать.
Невозможность для администратора иногда пойти наперекор _рекомендациям_, разработанным этими же разработчиками давным-давно - выставляет постгрес в очень невыгодном свете.
Ты уже заплатил разработчикам postgress за такую тяжелую сложную реализацию гибкого открытого решения?
Если бы постгрес был платным, и мы заплатили за него штуку баксов - это что-то изменило бы?
Вообще-то, когда оказалось, что сделать так в постгресе всё-таки нельзя, я думал, что я, наверное, действительно хочу странного, и мне сейчас объяснят, почему я не должен этого хотеть. Слышать же "они, бедные, забесплатно работают, не смогли такую сложнейшую фичу реализовать", да ещё и про постгрес (не mysql какой-нибудь) - очень странно, и не представляет никакого интереса, тут и так все знают, что он бесплатен.

Dasar

Соглашусь, что такие идеальные сферические желания - чтобы ПО умело все само - правильные, и ПО таким и будет буквально через дцать лет.
но в реальности пока такое ПО не получается, потому что пользователи начинают пугаться - когда им предлагают инструмент у которого 1001 настройка и 1001 кнопка.

6yrop

Полного каскадного удаления нет даже в MS SQL Server 2005, поэтому ссылка на бесплатность постгреса, действительно, звучит странно.
to : в чем проблема считать метаданные о таблицах и форенкеях и сгенерить скрипты, я делал подобное для MS SQL Server, это заняло 2-3 часа на C#.

kruzer25

но в реальности пока такое ПО не получается, потому что пользователи начинают пугаться - когда им предлагают инструмент у которого 1001 настройка и 1001 кнопка
Кого-то уже напугало разнообразие команд в постгресе?
Сильно сомневаюсь, потому что 90% пользователей (а может быть, и больше) даже и не смотрят на то, какие команды есть в постгресе, а используют стандартный SQL.
Впрочем, например, я и о SQL практически не думал последние годы, потому что ORM.
Постгрес - это всё-таки не для простых конечных пользователей продукт, а для разработчиков. У него нет ни одной кнопки, а количество настроек я и не предлагаю увеличивать. Сильно сомневаюсь, что одна дополнительная команда (или даже сотня дополнительных команд) кого-нибудь смутила.

Dasar

Сильно сомневаюсь, что одна дополнительная команда (или даже сотня дополнительных команд) кого-нибудь смутила.
oracle меня например пугает, потому что в итоге из-за наличия этих 1001 команд никто не знает тех 10, которые действительно необходимо знать.

kruzer25

в чем проблема считать метаданные о таблицах и форенкеях и сгенерить скрипты
В том, что надо это сделать.
я делал подобное для MS SQL Server, это заняло 2-3 часа на C#
Некоторое время уходит только на то, чтобы понять, как оно там хранится, методом тыка.

kruzer25

oracle меня например пугает, потому что в итоге из-за наличия этих 1001 команд никто не знает тех 10, которые действительно необходимо знать
Что-то я не пойму, если база понимает обычные SQL-запросы - зачем вообще смотреть на эти 1001 команду и искать те 10, которые действительно нужны?

6yrop

методом тыка
а поиском не пробовал пользоваться?
в мс сиквеле для этого виьюхи и хранимые процедуры есть

katrin2201

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

klyv

а сгенерировать DDL и запихать в VCS - недостаточно разве?

katrin2201

Еще надо уметь пихать ddl из vcs обратно в бд.
Дропать при этом всю схему нельзя, ибо там 5-10 гигов нужных для разработки данных. Соответственно надо уметь ее рефрешить.

sinet

Скрипт для выгрузки/загрузки переджей в файлы за полчаса пишется.
А вот хранить структуру БД в свн я не решился.
Написал скрипт сравнивающий 2 схемы, а потом ручками пишу алерты.

katrin2201

В моем случае это не совсем так.
- У нас оракл, и в нем туева хуча схем. Кросс-депенденси между схемами далеко не редкость.
- В свне надо хранить часть данных из таблиц (некие "метаданные", которые критичны для работы системы) так, чтобы в случае чего их можно было относительно удобно мерджить.
- Некоторые server-specific куски ddl'я (storage extents, etc) хочется вырезать.
- В довершение всего, формат в котором ddl хранится на винте фиксирован, и в итоге мне еще надо, например, уметь разбивать идущие подряд стейтменты на отдельные.
Кстати, если все эти требования убрать, то писать вообще по сути ничего не надо. Есть sql*plus и пицот тыщ утилит, которые умеют дампить схему в понимаемый им формат.

SCIF32

для постгреса есть apgdiff - вполне сносно работает
Оставить комментарий
Имя или ник:
Комментарий: