Подтвердить что ты не робот

Как обеспечить соблюдение ссылочной целостности при однократном наследовании?

Я читал некоторые из ответов Билла Карвина о одиночном наследовании таблицы и думаю, что этот подход будет хорошо для настройки, которую я рассматриваю:

Playlist
--------
id AUTO_INCREMENT
title

TeamPlaylist
------------
id REFERENCES Playlist.id
teamId REFERENCES Team.id

UserPlaylist
------------
id REFERENCES Playlist.id
userId REFERENCES User.id

PlaylistVideo
-------------
id
playlistId REFERENCES Playlist.id
videoId REFERENCES Video.id

Все параметры CASCADE установлены на DELETE, которые будут корректно работать, когда удаляется Playlist, однако, что происходит, если удаляется User или Team?

т. Если a User удаляется, строки в UserPlaylist будут удалены, но ссылки в строках в Playlist и PlaylistVideo останутся. Я думал об обеспечении этого как TRIGGER AFTER DELETE, но не существует способа узнать, вызвал ли запрос удаления, потому что был удален Playlist или удалено User.

Каков наилучший способ обеспечения целостности в этой ситуации?

Изменить (предоставлено ERD)

enter image description here

4b9b3361

Ответ 1

На мой взгляд, проблема в том, что ваши таблицы User и Team - это те, которые должны иметь таблицу супертипа (например, Party), а не таблицы списка воспроизведения.

Как вы указали, выполнение "наследования таблиц" в плейлистах происходит со штрафами при попытке выяснить, что удалить. Все эти проблемы уходят, когда вы перемещаете наследование до уровня пользователя/команды.

Вы можете увидеть этот ответ для более подробной информации о супертипировании/подтипинге.

Извините, что не поставлял код, так как я не знаю синтаксиса MySQL наизусть.

Основная концепция заключается в том, что таблица супертипов позволяет реализовать тип полиморфизма базы данных. Когда таблица, с которой вы работаете, должна ссылаться на какую-либо группу подтипов, вы просто делаете FK вместо этого супертипом, и это автоматически дает вам желаемое "только одно из них за раз" деловое ограничение, Тип супер имеет отношение "один к нулю" или "один к одному" с каждой из таблиц подтипа, и каждая таблица подтипов использует то же значение в PK, что и PK из таблицы супертипа.

В вашей базе данных, имея только одну таблицу Playlist с FK до Party (PartyID), вы легко выполнили свое бизнес-правило на уровне базы данных без триггеров.

Ответ 2

Что вы можете сделать, это реализовать триггеры в таблицах Users и Team, которые выполняются, когда строки удаляются из:

Таблица пользователей:

DELIMITER $$
CREATE TRIGGER user_playlist_delete 
BEFORE DELETE ON User FOR EACH ROW
BEGIN
    DELETE a FROM Playlist a
    INNER JOIN UserPlaylist b ON a.id = b.id AND b.userId = OLD.id;
END$$
DELIMITER ;

Таблица команд:

DELIMITER $$
CREATE TRIGGER team_playlist_delete 
BEFORE DELETE ON Team FOR EACH ROW
BEGIN
    DELETE a FROM Playlist a
    INNER JOIN TeamPlaylist b ON a.id = b.id AND b.teamId = OLD.id;
END$$
DELIMITER ;

Что эти триггеры будут делать, каждый раз, когда запись удаляется из одной из этих таблиц, операция DELETE будет автоматически выполняться в таблице Playlists с помощью id, которая должна быть удалена (через внутреннее соединение).

Я тестировал это, и он отлично работает.

Ответ 3

OK Я вижу, что вы хотите здесь... то, что вы хотите сделать, это запустить запрос типа

DELETE FROM playlist
WHERE       id 
NOT IN      (
    SELECT  id
    FROM    UserPlayList
    UNION
    SELECT  id
    FROM    TeamPlayList
)

после того, как строка удалена из пользователей или команд

Ответ 4

Ответ Zane Bien довольно очевиден и превосходный. Но у меня есть идея сделать это без использования триггера, потому что триггер имеет много проблем.

Используете ли вы язык программирования? Если да, то

Используйте один transaction и создайте свою базу данных auto commit false

напишите запрос удаления для ссылочных строк в списке воспроизведения и в списке воспроизведения. Вручную вы должны сначала написать этот запрос, используя этот идентификатор ссылки (с условием) и запустите его.

Теперь подготовьте другой запрос для своей основной задачи, то есть удалите пользователя, а строки в UserPlaylist будут удалены автоматически (из-за опции CASCADE DELETE). Теперь запустите свой второй запрос и commit.

Наконец, сделайте свою транзакцию auto commit true.

Он работает успешно, надеюсь, что это будет полезно.