web-dev-qa-db-fra.com

Puis-je avoir une clé étrangère référençant une colonne dans une vue dans SQL Server?

Dans SQL Server 2008 et donné

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

est-il possible de définir TableZ(A_or_B_ID, Z_Data) de telle sorte que la colonne Z.A_or_B_ID soit limitée aux valeurs trouvées dans ViewC? Cela peut-il être fait avec une clé étrangère contre la vue?

81
marc

Vous ne pouvez pas référencer une vue dans une clé étrangère.

101
Brian Fisher

Dans les anciennes éditions de SQL Server, les clés étrangères n'étaient possibles que via des déclencheurs. Vous pouvez imiter une clé étrangère personnalisée en créant un déclencheur d'insertion qui vérifie si la valeur insérée apparaît également dans l'une des tables pertinentes.

24
lorin_f

Si vous avez vraiment besoin de A_or_B_ID dans TableZ, vous avez deux options similaires:

1) Ajoutez nullable A_ID et B_ID colonnes vers le tableau z, faites A_or_B_ID une colonne calculée en utilisant ISNULL sur ces deux colonnes, et ajoutez une contrainte CHECK de telle sorte qu'une seule parmi A_ID ou B_ID est non nulle

2) Ajoutez une colonne TableName à la table z, contrainte de contenir A ou B. maintenant, créez A_ID et B_ID en tant que colonnes calculées, qui ne sont pas non nulles lorsque leur table appropriée est nommée (en utilisant l'expression CASE). Faites-les persister aussi

Dans les deux cas, vous avez maintenant A_ID et B_ID colonnes qui peuvent avoir les clés étrangères appropriées aux tables de base. La différence réside dans le calcul des colonnes. De plus, vous n'avez pas besoin de TableName dans l'option 2 ci-dessus si les domaines des 2 colonnes ID ne se chevauchent pas - tant que votre expression de cas peut déterminer quel domaine A_or_B_ID tombe dans

(Merci au commentaire d'avoir corrigé ma mise en forme)

15

Désolé, vous ne pouvez pas accéder à une vue dans SQL Server.

8
Jarrett Meyer

Il existe une autre option. Traitez TableA et TableB comme des sous-classes d'une nouvelle table appelée TablePrime. Ajustez les valeurs d'ID de TableB afin qu'elles ne coïncident pas avec les valeurs d'ID de TableA. Transformez l'ID dans TablePrime en PK et insérez tous les ID de TableA et de TableB (ajustés) dans TablePrime. Faire en sorte que TableA et TableB aient des relations FK sur leur PK avec le même ID dans TablePrime.

Vous avez maintenant le modèle de supertype/sous-type et pouvez faire des contraintes à TablePrime (quand vous voulez soit-A-ou-B) ou à l'une des tables individuelles (quand vous voulez seulement A ou niquement B).

Si vous avez besoin de plus de détails, veuillez demander. Il existe des variantes qui vous permettront de vous assurer que A et B s'excluent mutuellement, ou peut-être que la chose avec laquelle vous travaillez peut être à la fois en même temps. Il est préférable de formaliser cela dans les FK si possible.

4
ErikE

Désolé, au sens strict du mot, non, vous ne pouvez pas définir de clés étrangères sur les vues. Voici pourquoi:

InnoDB est le seul moteur de stockage intégré pour MySQL qui dispose de clés étrangères. Toute table InnoDB sera enregistrée dans information_schema.tables avec engine = 'InnoDB'.

Les vues, bien qu'elles soient enregistrées dans information_schema.tables, ont un moteur de stockage NULL. Il n'y a aucun mécanisme dans MySQL pour avoir des clés étrangères sur une table qui a un moteur de stockage non défini.

Merci!

1

Il est plus facile d'ajouter une contrainte qui fait référence à une fonction définie par l'utilisateur qui effectue la vérification pour vous, fCheckIfValueExists (columnValue) qui renvoie true si la valeur existe et false si elle ne l'est pas.

L'avantage est qu'il peut recevoir plusieurs colonnes, effectuer des calculs avec elles, accepter des valeurs nulles et accepter des valeurs qui ne correspondent pas précisément à une clé primaire ou comparer avec les résultats des jointures.

L'inconvénient est que l'optimiseur ne peut pas utiliser toutes ses astuces de clé étrangère.

1
Camilo J