2008-10-01 6 views
6

Ich arbeite an einer Datenbank, die Computer und ihre Benutzer darstellen muss. Jeder Computer kann mehrere Benutzer haben, und jeder Benutzer kann mehreren Computern zugeordnet werden. Es handelt sich also um eine klassische Viele-zu-Viele-Beziehung. Es muss jedoch auch ein Konzept eines "primären" Benutzers geben. Ich muss in der Lage sein, mich dem primären Benutzer anzuschließen, um alle Computer mit ihren primären Benutzern aufzulisten. Ich bin mir nicht sicher, was der beste Weg dies in der Datenbank zu strukturieren:Viele-zu-viele mit "Primär"

1) Wie ich gerade mache: Verknüpfungstabelle mit einer booleschen IsPrimary-Spalte. Das Verbinden erfordert etwas wie ON (c.computer_id = l.computer_id UND l.is_primary = 1). Es funktioniert, aber es fühlt sich falsch an, weil es nicht einfach ist, die Daten auf nur einen primären Benutzer pro Computer zu beschränken.

2) Ein Feld in der Computertabelle, das direkt auf eine Benutzerzeile zeigt, alle Zeilen in der Benutzertabelle repräsentieren nicht primäre Benutzer. Dies stellt die Einschränkung für einen primären Computer pro Computer besser dar, macht es jedoch schwieriger, eine Liste von Computerbenutzern zu erstellen.

3) Ein Feld in der Computertabelle, das mit einer Zeile in der Verknüpfungstabelle verknüpft ist. Fühlt sich komisch an ...

4) Noch etwas?

Was ist der "relationale" Weg, diese Beziehung zu beschreiben?

EDIT: @Mark Brackett: Die dritte Option scheint mir jetzt viel weniger seltsam, dass Sie gezeigt haben, wie schön es aussehen kann. Aus irgendeinem Grund dachte ich nicht einmal daran, einen zusammengesetzten Fremdschlüssel zu verwenden, also dachte ich, ich müsste eine Identitätsspalte auf der Verknüpfungstabelle hinzufügen, damit es funktioniert. Sieht gut aus, danke!

@ j04t: Cool, ich bin froh, dass wir jetzt auf # 3 zustimmen.

+0

warum es schwer, zeigen? – albertein

+0

Da die Verknüpfungstabelle nicht alle Benutzer für einen bestimmten Computer enthält. –

Antwort

7

Option 3, obwohl es seltsam fühlen, ist in der Nähe zu dem, was Sie modellieren möchten. Sie würden so etwas wie:

User { 
    UserId 
    PRIMARY KEY (UserId) 
} 

Computer { 
    ComputerId, PrimaryUserId 
    PRIMARY KEY (UserId) 
    FOREIGN KEY (ComputerId, PrimaryUserId) 
     REFERENCES Computer_User (ComputerId, UserId) 
} 

Computer_User { 
    ComputerId, UserId 
    PRIMARY KEY (ComputerId, UserId) 
    FOREIGN KEY (ComputerId) 
     REFERENCES Computer (ComputerId) 
    FOREIGN KEY (UserId) 
     REFERENCES User (UserId) 
} 

Welche Sie 0 oder 1 primäre Benutzer gibt (die PrimaryUserId kann NULL-Werte zulässt, wenn Sie möchten), das muss in Computer_User sein. Edit: Wenn ein Benutzer nur für 1 Computer primär sein kann, wird ein UNIQUE CONSTRAINT auf Computer.PrimaryUserId dies erzwingen.Beachten Sie, dass es nicht erforderlich ist, dass alle Benutzer auf einem Computer eine primäre Person sind (das wäre eine 1: 1-Beziehung und würde verlangen, dass sie sich in derselben Tabelle befinden).

Edit: Einige Abfragen Sie die Einfachheit dieses Entwurfs auf dem Computerbenutzer zur Liste Punkt 2

--All users of a computer 
SELECT User.* 
FROM User 
JOIN Computer_User ON 
    User.UserId = Computer_User.UserId 
WHERE 
    Computer_User.ComputerId = @computerId 

--Primary user of a computer 
SELECT User.* 
FROM User 
JOIN Computer ON 
    User.UserId = Computer.PrimaryUserId 
WHERE 
    Computer.ComputerId = @computerId 

--All computers a user has access to 
SELECT Computer.* 
FROM Computer 
JOIN Computer_User ON 
    Computer.ComputerId = Computer_User.ComputerId 
WHERE 
    Computer_User.UserId = @userId 

--Primary computer for a user 
SELECT Computer.* 
FROM Computer 
WHERE 
    PrimaryUserId = @userId 
+0

Der FK Computer -> CompUser erzwingt, dass der Hauptbenutzer eines Computers tatsächlich einer der Benutzer dieses Computers ist. Strenge ist gut :) – helios

+0

Danke für den Beitrag. Es hat mich dazu gebracht, die Beziehung auf eine Weise zu betrachten, die zunächst fremd erscheint, aber wirklich gut funktioniert. –

+0

Ich mochte es! Aus theoretischer Sicht sagen wir hier, dass wir eine "Eins-zu-Viele" -Beziehung mit dem Namen "ist der Hauptnutzer des Computers ..." haben, zusätzlich zu der "Viele-zu-Viele" -Beziehung, die "ist ein Benutzer von Computer ". Hat jemand eine Beschränkung auf diesen Vorschlag gesehen? –

0

Da der primäre Benutzer eine Funktion des Computers und des Benutzers ist, würde ich dazu neigen, mit Ihrem Ansatz zu gehen, dass der primaryUser eine Spalte in der Verknüpfungstabelle ist.

Die andere Alternative, die ich mir vorstellen kann, ist eine primaryUser-Spalte direkt auf der Computer-Tabelle selbst zu haben.

0

Ich hätte eine andere Tabelle PRIMARY_USERS mit einzigartigen auf computer_id gemacht und machen beide computer_id und user_id Fremdschlüssel der Benutzer.

0

Entweder Lösung 1 oder 2 wird funktionieren. An dieser Stelle würde ich mich fragen, mit wem man leichter arbeiten kann. Ich habe beide Methoden in verschiedenen Situationen verwendet, obwohl ich in der Regel mit einem Flag in der Verknüpfungstabelle gehen und dann eine eindeutige Integritätsbedingung für computer_id und isPrimaryUser erzwingen würde. Auf diese Weise stellen Sie sicher, dass jeder Computer nur einen primären Benutzer hat.

+0

mit Ausnahme der offensichtlichen Fehler von nicht primären Benutzern mit duplizierten Computer-ID, ist PrimaryUser Werte .... –

+0

Implementieren Sie einfach einen zweiten eindeutigen Schlüssel, so dass user_id und isPrimaryUser auch eindeutig sein müssen. Hält alles zu Hause in einem Tisch. –

+0

IsPrimaryUser kann entweder 0 oder 1 sein. Daher hätte Ihr eindeutiger Benutzerschlüssel (UserId, IsPrimary) einen Benutzer * höchstens * 1 nicht primären Benutzer (UserId, IsPrimary = 0) und 1 primären Benutzer (UserId, IsPrimary = 1) . Ihre (ComputerId, IsPrimary) hat einen ähnlichen Fehler. –

0

2 fühlt sich richtig an, aber ich würde 1, 2 und 3 für die Leistung der Arten von Abfragen, die Sie normalerweise durchführen, und die Art der Datenmengen, die Sie haben, testen.

Als allgemeine Faustregel tendiere ich dazu, zu glauben, dass Sie bei einer Auswahl von Implementierungen nach Ihren Abfrageanforderungen suchen und Ihr Schema so entwerfen sollten, dass Sie die beste Leistung und Ressourcennutzung im häufigsten Fall erhalten.

In der seltenen Situation, in der Sie ähnliche Fälle haben, die gegensätzliche Implementierungen vorschlagen, verwenden Sie Ockhams Rasiermesser.

+0

Ich würde nicht zustimmen, dass Sie viel Auswahl haben, wenn es um relationale Modellierung geht. Es gibt * einen richtigen Weg und einen falschen Weg. Der falsche Weg könnte besser sein - aber es wird ein Wartungsproblem sein. Manchmal müssen wir diesen Kompromiss machen, aber es sollte eine bewusste Entscheidung sein. –

+0

Nur zu folgen - Option 2 ist * falsch *, weil es einem Benutzer ermöglichen würde, sowohl ein primärer Benutzer (in Computer.PrimaryUserId) als auch ein nicht primärer Benutzer (in Computer_User) für denselben Computer gleichzeitig zu sein Zeit. –

1

Edit - Ich dachte nicht richtig darüber die ersten 3 mal durch ... Ich stimme für - (Nummer 3 -Lösung)

Benutzer

user id (pk) 

Computer

computer id (pk) 
primary user id (fk -> computer users id) 

Computer-Benutzer

user id (pk) (fk -> user id) 
computer id (pk) (fk -> user id) 

Dies ist die beste Lösung, die ich denken kann, .

Warum ich dieses Design mag.

1) Da es sich um eine Beziehung zwischen Computern und Benutzern handelt, gefällt mir die Idee, einen Benutzer mehreren Computern als Hauptbenutzer zuordnen zu können. Dies tritt jedoch möglicherweise nie auf, wenn diese Datenbank verwendet wird.

2) Der Grund Ich mag nicht die primary_user auf den Link Tabelle mit

(computer_users.primary_user_id fk-> users.user_id) 

ist, einen Computer zu verhindern, dass immer mehrere Hauptnutzer haben.

Angesichts dieser Gründe Nummer 3 Lösung sieht besser aus, da Sie nie auf mögliche Probleme stoßen werde ich mit den anderen Ansätze sehen.

Lösung 1 Problem - Möglich, mehrere primäre Benutzer pro Computer zu haben.

Lösung 2 Problem - Computer verbindet sich mit einem primären Benutzer, wenn der Computer und Benutzer nicht miteinander verknüpft sind.

computer.primaryUser = user.user_id 
computer_users.user_id != user.user_id 

Lösung 3 Problem - Es scheint irgendwie seltsam, nicht wahr? Ansonsten kann ich an nichts denken.

Lösung 4 Problem - ich kann nicht auf eine andere Weise, es zu tun denken.


Dies ist die vierte Bearbeitung, so hoffe ich, es macht Sinn noch.

+0

Dies löst noch immer nicht das Problem, einen "primären" Benutzer zu bestimmen. – Mark

0

Wir haben eine ähnliche Situation in der Anwendung, in der ich arbeite, wo wir Konten haben, die viele Kunden haben können, aber nur einer sollte der primäre Kunde sein.

Wir verwenden eine Verknüpfungstabelle (wie Sie haben), aber haben einen Sequenzwert in der Verbindungstabelle. Der primäre Benutzer ist derjenige mit Sequenz = 1. Dann haben wir einen Index für diese Verknüpfungstabelle für AccountID und Sequenz, um sicherzustellen, dass die Kombination von AccountID und Sequence eindeutig ist (dadurch wird sichergestellt, dass keine zwei Kunden die Primäre sein können) auf einem Konto). So würden Sie haben:

LEFT JOIN c.computer_id = l.computer_id AND l.sequence = 1