2009-04-02 22 views
1

Ich versuche herauszufinden, ob es möglich ist, einen Fremdschlüssel auf diese Weise zu erstellen.Composite Foreign Key Frage

Zuerst gibt es zwei übergeordnete Tabellen in diesem Szenario.

Tabelle 1 hat eine PK int und eine weitere int-Spalte. In Kombination sind die beiden einzigartig.

Tabelle 2 hat eine PK int und eine weitere int-Spalte. In Kombination sind die beiden einzigartig.

Der paarweise Wert zwischen den beiden Ints ist, wie wir derzeit die untergeordneten Datensätze für jede Tabelle auswählen.

Tabelle 3 enthält einen Wert für die PK- und andere int-Spalte aus einer der ersten beiden Tabellen. Es ist zuverlässig auswählbar, da die beiden Felder, wenn beide bei einer Suche verwendet werden, für eine der obigen Tabellen eindeutig sind.

So suche ich ein FK oder möglicherweise zwei FK für dieses Szenario zu erstellen. Ich möchte in der Lage sein, kaskadierende Löschungen von einer der ersten Tabellen in die dritte Tabelle auszuführen, und möchte dies auch für die Entitätsbeziehungen in Entity Framework verwenden.

Bitte lassen Sie mich wissen, wenn dies keinen Sinn ergibt. Ich habe es mehrmals gelesen, und es ist so klar, wie ich es verstehe.

TABLE_A: 
    PK_FIELD int NOT NULL 
    OTHER_FIELD int NOT NULL, NOT IN TABLE_B.OTHER_FIELD 

TABLE_B: 
    PK_FIELD int NOT NULL 
    OTHER_FIELD int NOT NULL, NOT IN TABLE_A.OTHER_FIELD 

TABLE_C: 
    PK_FIELD int NOT NULL 
    OTHER_FIELD int NOT NULL IN (TABLE_A.OTHER_FIELD OR TABLE_B.OTHER_FIELD 

Was Sie versuchen zu tun definieren ist TABLE_C, so dass Sie Updates Kaskade könnte und löscht zwischen den Tabellen:

Dank

Antwort

0

Wenn Table3 alle Werte in Tabelle 1 UNION Table2 enthält, dann haben Sie eine inheritance scheme:

Table3 { (int id, int type) PK } 
Table1 { (int id, int type [CHECK type = 1]) FK Table3 } 
Table2 { (int id, int type [CHECK type = 2]) FK Table3 } 

Damit aus Table3 Löschen in geeigneter Weise zu Tabelle 1 oder Tabelle 2 kaskadiert werden.

Andernfalls, wenn Table3 nur eine Teilmenge von Table1 UNION Table2 ist, würde die Einführung von Table4 als vollständiger Satz funktionieren.

Table4 { (int id, int type [CHECK type IN (1,2)]) PK } 
Table1 { (int id, int type [CHECK type = 1]) FK Table4 } 
Table2 { (int id, int type [CHECK type = 2]) FK Table4 } 
Table3 { (int id, int type) FK Table4 } 

Um kaskadiert Löschungen handhaben, wenn Sie von Table4 zu löschen brauchen würde (auch wenn Sie einen Trigger auf Table3 tun könnte das für Sie zu handhaben).

Edit (weil ich denke, es ist ein wichtiger Punkt, seperate gesehen, aus den Kommentaren werden sollte):

Ja, das Problem dabei ist, dass eins und zwei sind die Eltern. Sie haben beide verwandte Datensätze in 3, was ein FK, kein PK für diesen Tisch wäre. Es scheint ziemlich unmöglich zu sein, eine FK-Beschränkung zu verwenden. Danke für die Antwort! - Chrisb (vor einer Stunde)

IMO - Ihr Datenmodell ist dann kaputt. Tabelle 1 und Tabelle 2 sind nicht verwandt, aber Sie versuchen, sie in derselben Spalte in Tabelle 3 zu stopfen. Wenn Table1 und Table2 irgendwie zusammenhängen, müssen Sie das modellieren.

Geben Sie entweder eine Elterntabelle (Tabelle4) ein, wenn sie verwandt sind, oder eine zweite Spalte in Tabelle3 (Tabelle1 FK, Tabelle2 FK) oder 2 Join-Tabellen, falls dies nicht der Fall ist. Versuchen Sie nicht, einen runden Stift in ein quadratisches Loch zu stecken - und versuchen Sie nicht, dies mit einem Abzug auszugleichen. ;)

+0

Ja, das Problem damit ist, dass eins und zwei die Eltern sind. Sie haben beide verwandte Datensätze in 3, was ein FK, kein PK für diesen Tisch wäre. Es scheint ziemlich unmöglich zu sein, eine FK-Beschränkung zu verwenden. Danke für die Antwort! – Chrisb

+0

IMO - Ihr Datenmodell ist dann kaputt. Tabelle 1 und Tabelle 2 sind nicht verwandt, aber Sie versuchen, sie in derselben Spalte in Tabelle 3 zu stopfen. Wenn Table1 und Table2 irgendwie zusammenhängen, sollte Table4 die Elterntabelle sein. –

+0

Ich stimme völlig zu, aber ich habe keine Kontrolle darüber. Danke für die Kommentare, sie bestätigen, was ich komplett dachte. – Chrisb

1

Wenn ich Sie richtig verstehe, haben Sie drei Tabellen wie folgt strukturiert . Aufgrund dessen, wie TABLE_A.OTHER_FIELD und TABLE_B.OTHER_FIELD definiert sind, garantieren Sie, dass es keine Überschneidungen zwischen ihnen gibt. Das Problem ist herauszufinden, welche Tabelle den Verweis auf TABLE_C hat.

Was Sie mit dieser Definition tun können, ist Kaskade von TABLE_A oder TABLE_B bis TABLE_C, da die Beziehung in dieser Richtung ziemlich klar ist. Die Kaskadierung von TABLE_C nach oben ist jedoch komplizierter, da Sie nicht wissen, zu welcher Tabelle eine Kaskade führen soll. Definieren Sie entweder zwei Felder in TABLE_C, um auf jede der anderen Tabellen zu verweisen, und dann können Sie die Beziehung zwischen allen drei Tabellen definieren, wobei Sie wissen, dass für einen bestimmten Datensatz nur ein oder zwei Tabellen verwendet werden, niemals alle drei. Alternativ können Sie Code verwenden, um herauszufinden, mit welcher Tabelle diese bestimmte Zeile verknüpft werden soll und entsprechend kaskadieren soll.

+0

Ja, das ist es genau. Es ist mir egal, dass ich von Tisch 3 zurückgehe. Wissen Sie, welche Art von T-SQL-Code ich für die Erstellung der Einschränkungen in Tabelle 3 benötigt? – Chrisb

+0

Ich bin mir nicht sicher, ob es eine Möglichkeit gibt, eine formale Einschränkung zu definieren, die Ihnen dies mit einer einzigen Spalte geben würde. Wenn Sie die Zwei-Spalten-Lösung verwenden, ist jedes Feld nullfähig, und es gibt eine Tabelleneinschränkung, die angibt, dass genau eines der beiden Felder null ist. – Elie

0

Ich weiß nicht, welche DBMS Sie verwenden, aber ich weiß keine, die Multi-Eltern akzeptieren. Sie können einen Index für Tabelle 3 definieren (um schneller zu sein) und das kaskadierende Löschen in Ihrer Anwendung implementieren.

+0

Ich benutze SQL Server 2005. – Chrisb