2010-12-23 3 views
6

i haben eine Tabelle mit dem Namen wie PartyChannel folgenden Spalten mitConditional Fremdschlüssel in SQL

ID, ChannelID, ChannelType 

ChannelID speichert MailID oder PhoneID oder EmailID je nach ChannelType.

also wie kann ich einen Fremdschlüssel zwischen PartyChannel und allen drei Tabellen (Mail, E-Mail und Telefon) abhängig vom channelType erstellen.

+3

mailid, PhoneID, EMAILID sind drei verschiedene Domänen und kann nicht, sollte nicht eine einzige ChannelID Säule modelliert werden. Das ist fundamentales Zeug. – onedaywhen

Antwort

4

AFAIK, dies ist mit Standard-Fremdschlüsseln nicht möglich. Sie können jedoch mithilfe von Triggern etwas implementieren, um die Datenintegrität sicherzustellen. Im Wesentlichen würde der Trigger das Vorhandensein eines "Fremdschlüssels" in der referenzierten Tabelle prüfen - der Wert, der vorhanden sein muss -, wenn ein Einfügen oder Aktualisieren der referenzierenden Tabelle stattfindet. Ebenso kann ein Löschvorgang aus der referenzierten Tabelle einen Trigger enthalten, der nach Datensätzen in der referenzierenden Tabelle sucht, die den gelöschten Schlüssel verwenden.

Update: Obwohl ich ging richtig für die "Antwort" stimme ich mit dem Kommentar von @onedaywhen, dass dies tatsächlich ein Design-Problem ist, das Sie wahrscheinlich überdenken Sie Ihr Design machen sollte. Das heißt, Sie sollten drei verschiedene Spalten anstelle einer Spalte haben, die auf drei Tabellen verweist. Sie würden einfach die anderen beiden Spalten leer lassen, wenn eine gefüllt ist, was wiederum die Verwendung von Standard-Fremdschlüsseln ermöglichen würde. Jede Sorge, dass dies zu viel Platz verbrauchen würde, ist albern; es stellt einen schwerwiegenden Fall einer vorzeitigen Optimierung dar - es wird einfach keine Rolle spielen.

7

Sie können PERSISTED COMPUTED Spalten mit einer Case-Anweisung verwenden, aber am Ende kauft es nichts als Overhead.

Die beste Lösung wäre, sie als drei verschiedene Werte zu modellieren, um damit zu beginnen.

CREATE TABLE Mails (MailID INTEGER PRIMARY KEY) 
CREATE TABLE Phones (PhoneID INTEGER PRIMARY KEY) 
CREATE TABLE Emails (EmailID INTEGER PRIMARY KEY) 

CREATE TABLE PartyChannel (
    ID INTEGER NOT NULL 
    , ChannelID INTEGER NOT NULL 
    , ChannelType CHAR(1) NOT NULL 
    , MailID AS (CASE WHEN [ChannelType] = 'M' THEN [ChannelID] ELSE NULL END) PERSISTED REFERENCES Mails (MailID) 
    , PhoneID AS (CASE WHEN [ChannelType] = 'P' THEN [ChannelID] ELSE NULL END) PERSISTED REFERENCES Phones (PhoneID) 
    , EmailID AS (CASE WHEN [ChannelType] = 'E' THEN [ChannelID] ELSE NULL END) PERSISTED REFERENCES Emails (EmailID) 
) 

Haftungsausschluss

nur weil Sie bedeutet nicht, Sie sollten.

+0

Das ist ziemlich wild. Funktioniert es in allen wichtigen SQL-Implementierungen? –

+0

@Mark: es funktioniert mit SQL Server 2005 & 2008. Ansonsten habe ich ehrlich gesagt keine Ahnung, es war eine gute mentale Übung . Ein Haftungsausschluss könnte jedoch in Ordnung sein: * Nur weil Sie können, bedeutet nicht, dass Sie sollten! * –

+0

Es funktioniert in SQL Server, obwohl Ihr ChannelType sollte ein Char oder Varchar sein, anstatt ein int. Wieder - +1 - danke. Ziemlich interessantes und ungewöhnliches Zeug. Ich stimme immer noch @onedaywhen, dass dies kein gutes Design ist, aber ich schätze die Lektion in offbeat SQL, die Sie zur Verfügung gestellt haben! –

4

Untertyp Email, Mail, Phone zu Channel.

alt text

+0

Dies ist das Gen-Spec-Muster, wie es in einem relationalen Modell dargestellt ist. Das Diagramm veranschaulicht die Schlüssel schön. Gut gemacht. –