Проверить наличие внешних связей

Модераторы: kdv, CyberMax

Ответить
fmcoder
Сообщения: 46
Зарегистрирован: 24 сен 2007, 20:57

Проверить наличие внешних связей

Сообщение fmcoder » 07 окт 2007, 20:23

Есть небольшая проблема...

Имеем 1 таблицу (далее - основная) с полем id и еще кучей других полей, далее есть еще N таблиц (дополнительные) связанных с таблицей 1 по полю id.

Задача такова: при удалении из дополнительной таблицы, если больше ни одна из дополнительных таблиц не содержит данного id то удалить запись с этим id из основной таблицы.

Пока нашел 2 решения:
1. Просто попробовать удалить, в случае чего (если есть связи по этому id) вывалится эксепшн и ничего не удалится. Мне кажется как-то грубо :)

2. Прогнать "select count(*) from ... where id = myid" по всем доп. таблицам, если везде 0 записей то удалить из основной. Это по моему как-то долго и еще нужно нагенерить запросов для каждой таблицы. Или может можно как-то одним запросом сделать? Пробовал "select count(*) from "Table1", "Table2" where "id" = 1" говорит ambiguous field name...

Есть ли способы проще?

SAMZ
Сообщения: 128
Зарегистрирован: 21 мар 2005, 08:17

Сообщение SAMZ » 08 окт 2007, 06:51

В данном случае вместо select count(*) эффективнее работает exists
Я бы эти проверки организовал в одной процедуре и вызывал бы ее из триггеров после удаления в дочерних таблицах.

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Re: Проверить наличие внешних связей

Сообщение Dimitry Sibiryakov » 08 окт 2007, 07:51

fmcoder писал(а):Задача такова: при удалении из дополнительной таблицы, если больше ни одна из дополнительных таблиц не содержит данного id то удалить запись с этим id из основной таблицы.

Есть ли способы проще?
Просто и тупо пытайся удалить запись из основной таблицы и гаси исключение с помощью WHEN. Если подчиненных записей нет - она удалится. Если есть - никакие проверки не помогут.

Slavik
Сообщения: 115
Зарегистрирован: 17 янв 2007, 11:52

Re: Проверить наличие внешних связей

Сообщение Slavik » 08 окт 2007, 09:36

Я бы ещё ПЕРЕД удалением подчинённой записи делал блокировку мастер-записи (через update или select ... for update with lock), чтоб другим транзакциям неповадно было.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Re: Проверить наличие внешних связей

Сообщение WildSery » 08 окт 2007, 11:56

Slavik писал(а):Я бы ещё ПЕРЕД удалением подчинённой записи делал блокировку мастер-записи (через update или select ... for update with lock), чтоб другим транзакциям неповадно было.
Чего именно неповадно?

Slavik
Сообщения: 115
Зарегистрирован: 17 янв 2007, 11:52

Re: Проверить наличие внешних связей

Сообщение Slavik » 08 окт 2007, 12:18

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

Блокировка же мастер-записи даст по мордам второй конкурентной транзакции.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Re: Проверить наличие внешних связей

Сообщение WildSery » 08 окт 2007, 13:18

Slavik писал(а):Например, есть мастер-запись и две её подчинённые записи. Одна транзакция стартует и удаляет первую подчинённую запись, проверяет - ещё есть подчинённые записи, естественно удалять мастер-запись и не собирается. В это же время стартует другая транзакция и удаляет вторую подчинённую запись, проверка также не даёт удалить мастер запись, т.к. удаление, сделанное в первой транзакии для второй - не видны. Первая и вторая транзакции успешно коммитятся. В итоге, мастер-запись остаётся без подчинённых.
Чтобы так не было, удалять родителя надо отдельной транзакцией.
Slavik писал(а):Блокировка же мастер-записи даст по мордам второй конкурентной транзакции.
Блокировка даст по мордам всем, в итоге ни одну дочернюю запись нельзя будет удалить, пока не отпустят. Хорошо ли это?

fmcoder
Сообщения: 46
Зарегистрирован: 24 сен 2007, 20:57

Сообщение fmcoder » 08 окт 2007, 14:02

Всем спасибо за ответы!
А что за WHEN? Информации по нему найти не смог, слишком общеупотребительное слово... Я так думаю это то что надо (гасить исключения), просто пытаться удалить, если получится - удалится, если нет то нет и никаких проблем.

Насчет lock и нескольких транзакций одновременно это врядли. У меня система расчитана на работу на одном компьютере (и сервер и клиент), а кол-во программ-клиентов где-то от 3-х до 12, и то удалять может только одна (максимум 3) из них, остальные читают или update'ят, поэтому тут думаю можно не бояться конфликтов.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 08 окт 2007, 15:39

fmcoder писал(а):А что за WHEN?
Искать нужно было конкретно в синтаксисе PSQL-блоков. Ловля исключений в процедурах/триггерах.
Например,

Код: Выделить всё

delete from Table1 where id=:id;
when any do begin
  insert into log (id, val) values (:id, 'Not deleted');
end
Всместо ANY может быть указана конкретная ошибка.
fmcoder писал(а):то удалять может только одна (максимум 3) из них, остальные читают или update'ят, поэтому тут думаю можно не бояться конфликтов.
Конфликтов чего? Ты ж сам правильно сказал, что исключение на невозможность удаления можно просто давить и всё.

Slavik
Сообщения: 115
Зарегистрирован: 17 янв 2007, 11:52

Re: Проверить наличие внешних связей

Сообщение Slavik » 08 окт 2007, 17:31

WildSery писал(а):Чтобы так не было, удалять родителя надо отдельной транзакцией.
Можно и так, хоть и остаётся некоторая вероятность облома, не связанного с наличием подчинённых записей.
WildSery писал(а):Блокировка даст по мордам всем, в итоге ни одну дочернюю запись нельзя будет удалить, пока не отпустят. Хорошо ли это?
Автор, похоже, блокировок не боится ;)

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Re: Проверить наличие внешних связей

Сообщение WildSery » 08 окт 2007, 18:02

Slavik писал(а):Можно и так, хоть и остаётся некоторая вероятность облома, не связанного с наличием подчинённых записей.
Какого например?
Slavik писал(а):Автор, похоже, блокировок не боится ;)
Не понял. Почему он не боится? Все боятся :P

Slavik
Сообщения: 115
Зарегистрирован: 17 янв 2007, 11:52

Re: Проверить наличие внешних связей

Сообщение Slavik » 08 окт 2007, 18:54

WildSery писал(а):Какого например?
Сервер прилёг отдохнуть, сетка тоже устала... :D
WildSery писал(а):Не понял. Почему он не боится? Все боятся :P
Откуда ж я знаю. Говорит "можно не бояться конфликтов"... :lol:

fmcoder
Сообщения: 46
Зарегистрирован: 24 сен 2007, 20:57

Сообщение fmcoder » 08 окт 2007, 19:15

Спасибо, с when буду разбираться.

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

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 08 окт 2007, 22:08

изменения в один момент времени делаются только одной программой и т.п.
а одну программу может запустить только один человек с одного компа? :)

fmcoder
Сообщения: 46
Зарегистрирован: 24 сен 2007, 20:57

Сообщение fmcoder » 09 окт 2007, 02:21

kdv писал(а):
изменения в один момент времени делаются только одной программой и т.п.
а одну программу может запустить только один человек с одного компа? :)
Да, именно так.

Ответить