2013-03-31 10 views
5

Ich habe eine MySQL-Tabelle für Benutzer mit dem Primärschlüssel _id, und ich möchte Freundschaften (Sichtbarkeit auf Freundeslisten anderer Benutzer) als ein darstellen Tabelle mit Paaren von Fremdschlüsseln userId. Ich denke, so etwas wie:SQL Composite Primärschlüssel ohne Reihenfolge (Paar von ganzen Zahlen in jeder Reihenfolge muss eindeutig sein)

CREATE TABLE UserFriendships (
    userIdA INT NOT NULL, 
    userIdB INT NOT NULL, 
    PRIMARY KEY (userIdA, userIdB), 
    FOREIGN KEY (userIdA) REFERENCES Users(_id) 
    FOREIGN KEY (userIdB) REFERENCES Users(_id) 
) 

Es ist mein Verständnis, dass dies sowohl (userIdA = 2, userIdB = 7) und (userIdA = 7, userIdB = 2) erlauben wird als eindeutige Zeilen eingefügt werden. Ich möchte eine Zeile pro Freundschaft, also eine Zeile pro Paar userIds.

Weiß jemand, wie ich das verbessern könnte? Selbst wenn die obige Einschränkung erfüllt ist, muss ich eine Union erstellen, um eine Liste aller Freunde von Benutzer foo zu erhalten: SELECT userIdB AS friendUserId WHERE userIdA = foo UNION SELECT userIdA WHERE userIdB = foo. Ist dies der beste Weg, um diese Abfrage durchzuführen, oder sollte ich darüber nachdenken, mein Schema zu ändern?

+0

Wie gehen Sie mit der Hin- und Herbewegung um? – Strawberry

+4

Wäre mit jedem anderen DBMS recht einfach, aber bei MySQL kann ich mir nur eine Trigger-Lösung vorstellen, um dies zu verhindern. –

+0

@Strawberry Ich hatte nicht daran gedacht, aber ich kann eine separate Tabelle von FriendRequests einschließen, die, sobald sie reziprokiert sind, eine Einfügung in UserFriendships ergeben. Obwohl sie die gleichen Daten enthalten würden, scheint das überflüssig zu sein ... –

Antwort

4

können Sie ein TRIGGER BEFORE INSERT verwenden, um eine Geschäftsregel enfore:

  • userIdA ist immer der Benutzer mit der unteren ID und userIdB immer der Benutzer mit der höheren ID

diese Weise beiden Kombinationen (A, B) und (B, A) ergeben dieselbe Spaltenreihenfolge mit demselben Primärschlüssel.

DELIMITER | 
CREATE TRIGGER enforce_friendship_id_order BEFORE INSERT ON UserFriendships 
    FOR EACH ROW BEGIN 
    SET @lowerId := IF(NEW.userIdA < NEW.userIdB, NEW.userIdA, NEW.userIdB); 
    SET @higherId := IF(NEW.userIdA > NEW.userIdB, NEW.userIdA, NEW.userIdB); 
    SET NEW.userIdA = @lowerId; 
    SET NEW.userIdB = @higherId; 
    END; 
| 
DELIMITER ; 
+0

Huch. Upvote für eine funktionierende Lösung, aber ich denke, ich würde die Regel lieber unverstärkt lassen und Duplikate riskieren, als mich mit Triggern zu messen. Ich nehme an, das ist die Art von Ding, für die sie sind, aber es fühlt sich einfach nicht sauber an, weißt du? –

+1

nun ja, das ist einer der Anwendungsfälle, für die Trigger verwendet werden. Ich sehe nicht, wie eine Änderung in Ihrem Tabellenschema Ihnen helfen könnte, deshalb habe ich diese Antwort gepostet. Sie können die gleiche Geschäftsregel in Ihrem Anwendungscode anwenden, aber ich denke, dass sie zur Datenbank gehört. MySQL ist hier keine wirkliche Hilfe. – Kaii

+0

@MikeTurley "mischt" mit Auslösern so schlecht, wirklich? – Kaii

Verwandte Themen