Kann ich einen Fremdschlüssel haben, der auf eine Spalte in einer Ansicht in SQL Server verweist?


84

In SQL Server 2008 und gegeben

TableA(A_ID, A_Data)
TableB(B_ID, B_Data)
ViewC(A_or_B_ID, A_or_B_Data)

Ist es möglich, so zu definieren TableZ(A_or_B_ID, Z_Data), dass die Z.A_or_B_IDSpalte auf die in gefundenen Werte beschränkt ist ViewC? Kann dies mit einem Fremdschlüssel gegen die Ansicht erfolgen?

Antworten:


108

Sie können nicht auf eine Ansicht in einem Fremdschlüssel verweisen.


36
Ist dies eine Einschränkung von SQL Server oder ist es eine unvernünftige Sache zu wollen?
Aaron Anodide

1
@Brian Auch ich würde gerne wissen, ob dies eine Einschränkung eines SQL Servers oder eine unvernünftige Sache ist, da ich an dieser Stelle eine Ansicht mit Triggern emulieren möchte, nur um FK-Unterstützung zu erhalten (obwohl ich MySql verwende ).
Schlitten

4
Dies ist eine gute Antwort auf diese Folgefragen - stackoverflow.com/questions/3833150/…
Chris Halcrow

Ich bin mir nicht sicher, wie das eine gute Antwort auf diese Fragen ist. Es handelt sich um ein anderes DBMS und besagt, dass Ansichten zum Ausblenden von Schemadetails und zur Benutzerfreundlichkeit entwickelt wurden. Erstens, ok ... aber dies wäre nicht das erste, was solide Anwendungsfälle jenseits des ursprünglichen Designs findet. Zweitens bin ich mir nicht sicher, warum ein FK das nicht tun würde. Eine Ansicht kann eine beliebige Abfrage sein, die nicht einmal aus einer Tabelle gezogen werden muss. Es kann sich um eine Reihe von Konstanten handeln, die miteinander verbunden sind. Ein Fremdschlüssel scheint in diesem Fall verdammt sinnvoll zu sein. Wenn es einen Grund gibt, warum nicht, würde ich auf etwas Tieferes hoffen.
George Mauer

27

In älteren SQL Server-Editionen waren Fremdschlüssel nur über Trigger möglich. Sie können einen benutzerdefinierten Fremdschlüssel nachahmen, indem Sie einen Einfügetrigger erstellen, der prüft, ob der eingefügte Wert auch in einer der relevanten Tabellen angezeigt wird.


3
Willkommen bei StackOverflow. Ich habe Wert in Ihrer Antwort gefunden, da dies eine Problemumgehung darstellt, aber die richtige Antwort ist die akzeptierte, und die Frage ist älter als 4 Jahre. Ich stimme also nicht ab, wollte aber nicht ohne diesen Kommentar bleiben.
Jachguate

16

Wenn Sie wirklich brauchen A_or_B_ID in TableZ , haben Sie zwei ähnliche Möglichkeiten:

1) Fügen Sie der Tabelle z nullable A_IDund B_IDSpalten hinzu, A_or_B_IDerstellen Sie mit ISNULL eine berechnete Spalte für diese beiden Spalten und fügen Sie eine CHECK-Einschränkung hinzu, sodass nur eine vonA_IDB_ID null null ist oder nicht

2) Fügen Sie der Tabelle z eine TableName-Spalte hinzu, die entweder A oder B enthalten darf. Erstellen Sie nun A_IDundB_ID als berechnete Spalten, die nur dann nicht null sind, wenn die entsprechende Tabelle benannt wird (unter Verwendung des CASE-Ausdrucks). Machen Sie sie auch hartnäckig

In beiden Fällen haben Sie jetzt A_IDund B_IDSpalten, die geeignete Fremdschlüssel für die Basistabellen haben können. Der Unterschied besteht darin, welche Spalten berechnet werden. Außerdem benötigen Sie in Option 2 oben keinen Tabellennamen, wenn sich die Domänen der 2 ID-Spalten nicht überschneiden - solange Ihr Fallausdruck bestimmen kann, welche DomäneA_or_B_ID fallen

(Danke an den Kommentar zum Korrigieren meiner Formatierung)


Setzen Sie Wörter mit Unterstrichen in Back-Ticks: A_or_B_ID
Bill Karwin

Ich arbeite daran, einem Legacy-System einige Funktionen hinzuzufügen, und dies ist eine großartige Möglichkeit, alte und neue zusammenzufügen. Danke dir!
David Gunderson


4

Es gibt noch eine andere Option. Behandeln Sie TableA und TableB als Unterklassen einer neuen Tabelle namens TablePrime. Passen Sie die ID-Werte von TableB so an, dass sie nicht mit den ID-Werten von TableA übereinstimmen. Machen Sie die ID in TablePrime zur PK und fügen Sie alle (angepassten) IDs von TableA und TableB in TablePrime ein. Stellen Sie sicher, dass TableA und TableB auf ihrer PK FK-Beziehungen zu derselben ID in TablePrime haben.

Sie haben jetzt das Supertyp- / Subtyp-Muster und können TablePrime (wenn Sie entweder A oder B möchten ) oder eine der einzelnen Tabellen (wenn Sie nur A oder möchten) einschränken nur B .

Wenn Sie weitere Informationen benötigen, fragen Sie bitte. Es gibt Variationen, mit denen Sie sicherstellen können, dass sich A und B gegenseitig ausschließen, oder dass Sie mit beiden gleichzeitig arbeiten können. Es ist am besten, dies in den FKs zu formalisieren, wenn dies möglich ist.


2

Es ist einfacher, eine Einschränkung hinzuzufügen, die auf eine benutzerdefinierte Funktion verweist, die die Prüfung für Sie durchführt: fCheckIfValueExists (columnValue), die true zurückgibt, wenn der Wert vorhanden ist, und false, wenn dies nicht der Fall ist.

Der Vorteil ist, dass es mehrere Spalten empfangen, Berechnungen mit ihnen durchführen, Nullen akzeptieren und Werte akzeptieren kann, die nicht genau einem Primärschlüssel entsprechen, oder mit Ergebnissen von Verknüpfungen verglichen werden kann.

Nachteil ist, dass der Optimierer nicht alle seine Fremdschlüssel-Tricks verwenden kann.


1
Nachteil ist, dass der Optimierer nicht alle seine Fremdschlüssel-Tricks verwenden kann ... ... und dass die Funktion für jede Zeile ausgeführt wird, die Sie einfügen / aktualisieren (also nicht zu schön für Sets).
Jimbobmcgee

0

Entschuldigung, im engeren Sinne des Wortes können Sie keine Fremdschlüssel für Ansichten festlegen. Hier ist warum:

InnoDB ist die einzige integrierte Speicher-Engine für MySQL, die Fremdschlüssel enthält. Jede InnoDB-Tabelle wird in information_schema.tables mit engine = 'InnoDB' registriert.

Ansichten sind zwar in information_schema.tables registriert, verfügen jedoch über eine NULL-Speicher-Engine. In MySQL gibt es keine Mechanismen, um Fremdschlüssel in einer Tabelle mit einer undefinierten Speicher-Engine zu haben.

Vielen Dank!


Diese Frage bezieht sich auf SQL Server
George Mauer
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.