13

Ich habe einige Bill Karwin's Antworten zu single table inheritance lesen und denken diese Vorgehensweise für das Setup gut wäre ich überlege:Wie erzwinge die referenzielle Integrität bei der Vererbung einzelner Tabellen?

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 

Alle CASCADE Optionen DELETE gesetzt werden, die für korrekt funktionieren, wenn ein Playlist ist gelöscht, was passiert jedoch, wenn eine User oder Team gelöscht wird?

dh. Wenn eine User gelöscht wird, werden die Zeilen in UserPlaylist gelöscht, aber die referenzierten Zeilen in Playlist und PlaylistVideo bleiben erhalten. Ich dachte darüber nach, dies als TRIGGER AFTER DELETE durchzusetzen, aber es gibt keine Möglichkeit zu wissen, ob die Löschanforderung zustande kam, weil die Playlist gelöscht wurde oder wenn die User gelöscht wurde.

Was ist der beste Weg, um Integrität in dieser Situation zu erzwingen?

bearbeiten (Gestellt ERD)

enter image description here

+1

Ich verstehe nicht, wie UserPlaylist eine Vererbung von Playlist sein könnte. Sollte es nicht stattdessen eine Relationstabelle sein? – Sebas

+0

Ich verstehe deine Frage nicht. UserPlaylist bezieht sich nur auf Playlist, die ID kommt von Playlist.id. Hier sind einige weitere Fragen zu Single Table Inheritance - http://Stackoverflow.com/a/3383320/47278 –

+0

Der ganze Grund, warum Sie nicht möchten, dass ein Benutzer gelöscht wird, um Playlist- und Playlist-Videozeilen herauszunehmen, liegt daran, dass sie auch referenziert werden konnten durch andere userplaylist- oder teamplaylist-Aufzeichnungen. – WebChemist

Antwort

3

Meiner Ansicht nach ist das Problem, dass Ihre User und Team Tabellen diejenigen sind, die eine übergeordnete Tabelle (wie Party) haben sollten, nicht die Playlist-Tabellen.

Wie Sie bereits erwähnt haben, kommt es bei der "Tabellenvererbung" in Wiedergabelisten zu Strafen, wenn Sie herausfinden möchten, was Sie löschen möchten. All diese Probleme verschwinden, wenn Sie die Vererbung auf die Benutzer-/Teamebene verschieben.

Sie können this answer for more detail about supertyping/subtyping sehen.

Es tut mir leid, keinen Code zu liefern, da ich die MySQL-Syntax nicht auswendig kann.

Das grundlegende Konzept ist, dass die Supertype-Tabelle ermöglicht Ihnen, eine Datenbank Art von Polymorphie zu implementieren. Wenn die Tabelle, mit der Sie arbeiten, eine Verknüpfung mit einer Gruppe von Subtypen haben soll, stellen Sie einfach den FK-Punkt auf den Supertyp und Sie erhalten automatisch die gewünschte "nur eine von diesen gleichzeitig". Geschäftsbeschränkung. Der Super-Typ hat eine "Eins-zu-Null-Beziehung" mit jeder der Subtype-Tabellen, und jede Subtype-Tabelle verwendet den gleichen Wert in seiner PK wie die PK aus der Supertype-Tabelle.

In Ihrer Datenbank haben Sie mit nur einer Tabelle Playlist mit einem FK Party (PartyID) Ihre Geschäftsregel problemlos auf Datenbankebene ohne Trigger durchgesetzt.

+0

Dies ist ein guter Punkt und eine gute Idee. In diesem System unterscheidet sich ein Team jedoch stark von einem Benutzer. z.B. Ein Benutzer kann sich anmelden, ein Team kann nicht. Dies ist ein bestehendes System in der Produktion (während die Playlisten neu sind). Wenn ich es von Grund auf neu aufbauen würde, wäre das wahrscheinlich der richtige Weg. Aber ich muss darüber nachdenken, ob es sich lohnen würde, zu diesem Setup zu wechseln (dh Teams und Benutzer hätten derzeit überlappende IDs). Aber danke für den Vorschlag. –

+0

Das ist, wofür die Subtype-Tabellen sind: die Arten, wie sie unterschiedlich sind. Das eigentliche Problem beim Ändern besteht darin, die IDs für eine der Gruppen zu aktualisieren, indem Abhängigkeiten gelöscht und neu erstellt werden. Aber ich denke, es lohnt sich. :) – ErikE

+0

Danke für die Auswahl meiner Antwort! Was hat dich dazu bewogen, das zu entscheiden? – ErikE

4

OK ich sehe, was Sie hier wollen ... was Sie tun möchten, ist eine Abfrage wie

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

nach laufen entweder eine Zeile gelöscht von entweder Benutzern oder Teams

11

Was Sie tun können, implementieren Trigger auf Ihren Users und Team Tabellen, die exec ute, wenn Zeilen aus entweder gelöscht werden:

Benutzertabelle:

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 ; 

Team-Tabelle:

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 ; 

Was diese Trigger von einem ein Datensatz gelöscht wird tun jedes Mal ist, von diesen Tabellen wird eine DELETE Operation automatisch auf der Playlists Tabelle mit der id ausgeführt, die gerade gelöscht wird (über eine innere Verbindung).

Ich habe das getestet und es funktioniert super.

+0

brillante Lösung. habe es nicht myslef getestet, aber sieht solide aus.+1 – techtheatre

+0

Gute Idee Zane. Aus irgendeinem Grund hatte ich nicht darüber nachgedacht, die User- oder Team-Tabellen auszulösen - nur die UserPlaylist- oder TeamPlaylist-Tabellen. –

+0

Ich glaube nicht, dass dies der beste Weg ist, um das Problem zu lösen ... – ErikE

1

Die Antwort von Zane Bien ist ziemlich offensichtlich & superb.Aber ich habe eine Idee, dies ohne Verwendung von Trigger zu tun, weil Trigger viele Probleme hat.

Verwenden Sie eine Programmiersprache? Wenn ja, dann

einen einzigen transaction Verwenden und machen Sie Ihre Datenbank auto commit false

schreiben eine Lösch-Abfrage für die referenzierten Zeilen in Playlist und PlaylistVideo. Manuell muss man zuerst diese Abfrage schreiben, indem man diese Referenz-ID (mit where-Bedingung) verwendet und sie ausführt.

Bereiten Sie jetzt eine weitere Abfrage für Ihre Hauptaufgabe vor, d. H. Löschen Sie den Benutzer, und die Zeilen in UserPlaylist werden automatisch gelöscht (aufgrund der Option CASCADE DELETE).Jetzt führen Sie Ihre zweite Abfrage und commit.

Schließlich machen Sie Ihre Transaktion auto commit true.

Es funktioniert erfolgreich, hoffe es wird hilfreich sein.

Verwandte Themen