Angenommen, ich habe eine Tabelle A mit zwei Spalten: Eine ist eine ID für ThingA
und eine ist eine ID für ThingB
. Der Primärschlüssel ist (ThingA, ThingB)
.
Als nächstes habe ich eine zweite Tabelle, aber diesmal ist sie auf Einträge in Tabellen beschränkt A
, die haben ThingB = 3
. Der Primärschlüssel ist ThingA
, weil ThingB
eine Konstante von 3 ist.
Anfangs hatte ich gedacht, ich könnte einfach:
FOREIGN KEY (ThingA, 3) REFERENCES A(ThingA, ThingB)
Aber ich habe gelernt, dass dies nicht der Fall ist, und ich muss eine Spalte erstellen für ThingB
:
ThingB INT NOT NULL DEFAULT(3) CHECK(ThingB = 3)
Dann,
FOREIGN KEY (ThingA, ThingB) REFERENCES A (ThingA, ThingB)
Gibt es eine Alternative dazu, für die keine zusätzliche Spalte erforderlich ist, oder die DEFAULT + CHECK
? Eine Alternative ist eine persistierte, berechnete Spalte , aber ich hasse diese Idee auch, da es sich im Grunde genommen um einen Cheat handelt und immer noch eine neue Spalte mit physischem Speicher hinzugefügt wird. Obwohl es alleine INT
nicht groß sein wird, gibt es mehrere Millionen Zeilen, die es für mehrere Tabellen benötigen, und ich möchte die zusätzlichen Spalten lieber nicht beibehalten.
Hier ist eine Beispiel-DDL, um die Situation zu veranschaulichen:
CREATE TABLE Test1
(
ThingA INT NOT NULL,
ThingB INT NOT NULL,
PRIMARY KEY (ThingA, ThingB)
);
CREATE TABLE Test2
(
ThingAVal INT NOT NULL,
ThingBVal INT NOT NULL DEFAULT(3) CHECK(ThingBVal = 3),
Val INT NOT NULL,
FOREIGN KEY (ThingAVal, ThingBVal) REFERENCES Test1 (ThingA, ThingB)
);
Und ich habe eine db <> -Fiedel erstellt, die meine (aktuelle) Lösung demonstriert:
Wenn die Antwort "Nein" lautet, werde ich sie akzeptieren, aber ich bin gespannt, ob es noch andere Alternativen gibt.
quelle
TINYINT
, wenn die Anzahl der möglichen Werte vonThingB
klein ist.SMALLINT
On-Prod, ich wünschte nur, es gäbe einen besseren Weg, es zu assoziieren. Ich werde möglicherweiseA
ganz los , da ich es eigentlich nicht brauche, und mache einfach die referenzielle Integrität überThingA
, sodass ich es entfernen kannThingB
.UNIQUE
Einschränkung zu verwenden(ThingA, ThingB)
?Antworten:
Ich denke, die Kombination aus einem Ersatzschlüssel
dbo.Test1
und einem nach beiden ausgeführten TriggerINSERT
undUPDATE
Anweisungen, insbesondere einemINSTEAD OF
Trigger, ist hier die Antwort.Und könnte ungefähr so aussehen ( Geige ):
Schema
Nach dem
INSERT
AuslösenNach dem
UPDATE
Auslösenquelle
Wenn Sie den konstanten Wert von ThingB kennen, empfehle ich, die Spalte "ThingB" wegzulassen. Lassen Sie stattdessen die Geschäftslogik den konstanten Wert hinzufügen. Was genau der Wert ist, kann in einer anderen Tabelle oder in einer Einstellung gespeichert werden.
quelle
Sie sagten, Sie wollten einer Reihe von Tabellen, die auf diese Weise wieder mit Test1 verknüpft werden müssen, keine zusätzliche Spalte hinzufügen (z. B. ThingA, 3).
Wie wäre es, wenn Sie TestA eine persistierte berechnete Spalte hinzufügen, die den Wert ThingA anzeigt, wenn ThingB 3 ist, andernfalls null?
Dann verweist Ihr Fremdschlüssel nur auf die neue Spalte, basierend auf ThingA in der Referenzierungstabelle.
und
Mit anderen Worten - eine neue Spalte in Test1 anstelle einer neuen Spalte in Test2 (um '3' zu halten) und Test3 und ....
quelle
(case ThingB when 3 then cast(ThingA as int) else null end) persisted;
- Dies sollte sicherstellen, dass die berechnete Spalte als definiert istint
.Ich denke die Antwort ist nein.
Der Fremdschlüssel muss auf eine EINZIGARTIGE EINSCHRÄNKUNG in der Tabelle verweisen, auf die gemäß Books Online verwiesen wird
Es scheint, als könnte die Lösung ein gefilterter eindeutiger Index sein, aber das zählt nicht als Einschränkung.
Sie können es hier überprüfen:
Ich glaube nicht, dass Sie dies sicher tun können, ohne Daten zu duplizieren - Ihre Lösung scheint am besten zu sein (CHECK-Einschränkung für die Referenzierungstabelle)
Eine indizierte Ansicht basierend auf Test1 mit einem Filter für ThingB = 3 würde wahrscheinlich auch funktionieren, aber Sie würden eine andere Spalte beibehalten.
Normalerweise vermeide ich Trigger, da sie die referenzielle Integrität sowie andere Einschränkungen nicht erzwingen, aber es könnte der richtige Weg sein.
quelle