[mysql]2 таблицы + таблица соответствий, вопрос по удалению внутри...

iakobi91

Есть две таблицы (фотоальбомы и фотографии) и таблица соответствий, соотносящая ряды в разных таблицах друг другу.
Каждый элемент второй таблицы (фотография) может соответствовать сразу нескольким элементам в первой (альбом).
Как сделать удаление альбома так, что если фотография относится только к нему, то она бы удалялась, иначе удалялся бы только ряд в таблице соответствий?

slonishka

опиши подробней, как устроена вторая таблица (фотографии). там для каждого фотоальбома у одной и той же фотографии отдельная строка? или есть третья таблица соответствий, как написано в топике? или соответствия описаны во второй таблице?
с вариантами 2 и 3 все очевидно, поэтому у тебя наверное вариант 1?

iakobi91

topics:
id (data - все остальные столбцы)
pictures:
id (data)
correlation:
id picture_id topic_id

Geddi-S

1. Удаляем все записи из таблицы соответствий с данным id альбома
2. Удаляем те фотографии, для которых нет записей в таблице соответствий
3. Удаляем данный альбом
(П. 2 и 3 можно поменять местами)

pitrik2

1. Удаляем все записи из таблицы соответствий с данным id альбома
2. Удаляем те фотографии, для которых нет записей в таблице соответствий
3. Удаляем данный альбом
(П. 2 и 3 можно поменять местами)
1. Удаляем те фотографии, для которых есть запись в таблице соответствий
DELETE FROM t_photo, t_corr
WHERE t_photo.id = t_corr.photo_id AND t_corr.album_id = ?
2. Удаляем все записи из таблицы соответствий с данным id альбома
DELETE FROM t_corr
WHERE t_corr.album_id = ?
3. Удаляем данный альбом
DELETE FROM t_album
WHERE t_album.id = ?
пункты менять местами нельзя
1) пункт 1 моего варианта быстрее пункта 2 варианта , а остальные пункты совпадают
2) все эти действия надо делать в пределах одной транзакции, тоесть если какаято фотография не смогла удалиться то и не надо удалять вообще ничего
в варианте если второй пункт завалится, то придется откатывать первый пункт
в моем варианте откатывать ничего не придется

kruzer25

DELETE FROM t_photo, t_corr
WHERE t_photo.id = t_corr.photo_id AND t_corr.album_id = ?
Зашибись.
Вот быа фотография 1, которая лежала в альбоме1 и альбоме2.
После этого твоего запроса (когда удаляем альбом1) у нас из альбома2 она пропадёт, а в t_corr останется ведущая в никуда запись "фото1, альбом2".

pitrik2

Зашибись.
Вот быа фотография 1, которая лежала в альбоме1 и альбоме2.
После этого твоего запроса (когда удаляем альбом1) у нас из альбома2 она пропадёт, а в t_corr останется ведущая в никуда запись "фото1, альбом2".
ну если у вас база без внешних ключей то вам можно токо посочувствовать
а так сработает внешний ключ: в другой таблице есть ссылки на эту запись и запись удалена не будет
про первый вариант я тоже могу сказать, что если были фотографии не принадлежищие ни одному альбому, то они удалятся

kruzer25

ну если у вас база без внешних ключей то вам можно токо посочувствовать
а так сработает внешний ключ: в другой таблице есть ссылки на эту запись и запись удалена не будет
Ну ты даёшь.
1) Надо говорить о том, что должны быть внешние ключи, не все БД их поддерживают.
2) Ты и всё остальное так же делаешь? Типа insert into table(id,value) values(1,2 а если там такая запись уже есть - пусть не вставится, мне не страшно.

kruzer25

Да, и ещё - пусть есть внешние ключи, а ещё есть вполне адекватные настройки драйвера БД - "если возникла ошибка - умереть и записать ошибку в лог/на экран". Что тогда, при удалении альбома всё помирать будет?

pitrik2

есть вполне адекватные настройки драйвера БД - "если возникла ошибка - умереть и записать ошибку в лог/на экран"
впервые про такое слышу
ничего адекватного тут не вижу

pitrik2

1) Надо говорить о том, что должны быть внешние ключи, не все БД их поддерживают
есть БД которые не держат внешние ключи?
очень интересно
подозреваю что такие БД и sql не держат

pitrik2

Типа insert into table(id,value) values(1,2 а если там такая запись уже есть - пусть не вставится, мне не страшно.
а ты каждый раз перед инсертом спрашиваешь есть ли там уже такая запись?
я валяюсь

kruzer25

а ты каждый раз перед инсертом спрашиваешь есть ли там уже такая запись?
Когда мне говорят "добавить новую запись и сделать ему id такой-то", я не говорю "отправил запрос к бд, вроде добавилось", я говорю "такая запись уже есть/успешно добавил запись/не получилось добавить запись, ошибка такая-то".

kruzer25

В любом случае, надо сначала сказать "для этого запроса надо сделать, чтобы были foreign keys такие-то".
Может, человек и не знает, что это такое.

kruzer25

подозреваю что такие БД и sql не держат
В mysql они поддерживаются только начиная с 3.23.44 и только в InnoDB.

kruzer25

С википедии:
Вне́шний ключ (англ. foreign key) — понятие теории реляционных баз данных, поле (атрибут) таблицы, предназначенное для хранения значения первичного ключа таблицы, связанной с данной. С помощью внешних ключей в реляционных БД организуются связи между таблицами.
...
Развитые СУБД поддерживают автоматический контроль ссылочной целостности на внешних ключах.
То есть, вообще-то, foreign key-и предназначены совсем не для того, чтобы удалять только то, на что там нет ссылок; этот "автоматический контроль целостности" - всего лишь фича; и фича для контроля целостности, чтобы ничего не упало, если сделать всё неправильно, а не для повседневного использования.

pitrik2

Когда мне говорят "добавить новую запись и сделать ему id такой-то", я не говорю "отправил запрос к бд, вроде добавилось", я говорю "такая запись уже есть/успешно добавил запись/не получилось добавить запись, ошибка такая-то".
ну дык я тож так не говорю
во-первых драйвер возвращает количество добавленных
во-вторых всегда вернется код ошибки по которому понятно что произошло
по остальному: не знал, что в mysql не так давно появились эти ключи
дурацкая СУБД

kruzer25

Ты используешь защиту от каких-то падений для своих ежедневных грязных делишек, уже это плохо.
Потому что так поставленную автором задачу можно решить и следующим способом:
delete * from `links` where albumid=123;
delete * from `photos`;
delete * from `albums`;
а mysql сам поймёт, что там можно удалять, а что - нельзя (и вполне возможно, что до того, как у тебя будет возможность эту ошибку перехватить, завоет сирена и на экране появятся большие красные буквы "попытка удалить запись, на которую кто-то ссылается!")

kruzer25

Если есть цель сделать всё максимально красиво, не полагаясь на защиту от удаления записей, на которые кто-то ссылается, и на то, что записи, на которые никто не ссылается, никому не нужны:
delete `pictures` from `pictures`,`correlation` where `pictures`.`id`=`correlation`.`picture_id` and `correlation`.`topic_id`=123 and `pictures`.`id` not in (select `pictures`.`id` from `pictures`,`correlation` where `pictures`.`id`=`correlation`.`picture_id` and `correlation`.`topic_id`!=123);
delete `correlation` from `correlation` where `correlation`.`topic_id`=123;
delete `topics` from `topics` where `topics`.`id`=123;
Тем, кто будет что-то говорить про скорость - оптимизатор сведёт различия к нулю, зато у меня гораздо более human-readable и не полагается на какие-то сайд-эффекты (типа "если попытаться удалить запись, на которую кто-то ссылается - это, конечно, неправвильно, но она не удалится, но при этом выполнение будет продолжено, и критическая ошибка не возникнет").
ЗЫ: Первый запрос - удаляем все pictures, которые есть в нужном topic, и которых больше нет ни в одном topic. Второй запрос - удаляем все correlations для нужного topic. Третий - удаляем сам topic.

kruzer25

во-первых драйвер возвращает количество добавленных
Он уже ничего не возвращает, он уже сказал "ошибка!", записал её в лог и сделал exit.

iakobi91

1. Удаляем все записи из таблицы соответствий с данным id альбома
2. Удаляем те фотографии, для которых нет записей в таблице соответствий
3. Удаляем данный альбом
(П. 2 и 3 можно поменять местами)

Туплю. Запрос для второго действия не могу придумать...

kruzer25

delete `pictures` from `pictures` where `pictures`.`id` not in (select `correlations`.`picture_id` from `correlations`).
Но моё решение лучше

iakobi91

Да, пасиб всем большое. Все переварил
ЗЫ надо больше спать...
Оставить комментарий
Имя или ник:
Комментарий: