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


84

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 de TableZ(A_or_B_ID, Z_Data)telle sorte que la Z.A_or_B_IDcolonne soit contrainte aux valeurs trouvées dans ViewC? Cela peut-il être fait avec une clé étrangère contre la vue?

Réponses:


108

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


37
est-ce une limitation du serveur SQL ou est-ce une chose déraisonnable à vouloir?
Aaron Anodide

1
@Brian Je serais également intéressé de savoir s'il s'agit d'une limitation d'un serveur SQL ou d'une chose déraisonnable à vouloir car à ce stade, je suis sur le point d'émuler une vue en utilisant des déclencheurs juste pour obtenir le support FK (bien que j'utilise MySql ).
Traîneau

4
C'est une bonne réponse à ces questions de suivi - stackoverflow.com/questions/3833150/…
Chris Halcrow

Je ne sais pas comment c'est une bonne réponse à ces questions ... il s'agit d'un SGBD différent et dit que les vues ont été conçues pour cacher les détails du schéma et la commodité de l'utilisateur. Tout d'abord, d'accord ... mais ce ne serait pas la première chose à trouver des cas d'utilisation solides au-delà de la conception initiale. Deuxièmement, je ne sais pas pourquoi un FK ne ferait pas cela. Une vue peut être n'importe quelle requête qu'elle n'a même pas à extraire d'une table, cela peut être un groupe de constantes unies ensemble ... une clé étrangère semble sacrément sensée dans ce cas. S'il y a une raison pourquoi pas, j'espère quelque chose de plus profond.
George Mauer le

27

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.


3
Bienvenue dans StackOverflow. J'ai trouvé la valeur dans votre réponse car fournit une solution de contournement, mais la bonne réponse est celle acceptée, et la question a plus de 4 ans, donc je ne vote pas mais je ne voulais pas partir sans ce commentaire.
jachguate

16

Si vous avez vraiment besoin A_or_B_IDde TableZ, vous avez deux options similaires:

1) Ajoutez des colonnes Nullable A_IDet B_IDà la table z, créez A_or_B_IDune colonne calculée en utilisant ISNULL sur ces deux colonnes, et ajoutez une contrainte CHECK de telle sorte qu'un seul parmi A_IDou B_IDne soit pas nul

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

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

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


Mettez les mots avec des traits de soulignement dans les back-ticks: A_or_B_ID
Bill Karwin

Je travaille sur l'ajout de fonctionnalités à un système hérité, et c'est un excellent moyen de patcher l'ancien et le nouveau ensemble. Merci!
David Gunderson


4

Il y a 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. Faites de l'ID dans TablePrime le PK et insérez tous les ID (ajustés) de TableA et TableB 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 créer des contraintes sur TablePrime (lorsque vous voulez soit-A-ou-B ) ou l'une des tables individuelles (lorsque vous voulez seulement A ou seulement 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 sont mutuellement exclusifs, ou peut-être que la chose avec laquelle vous travaillez peut être les deux en même temps. Il est préférable de formaliser cela dans les FK si possible.


2

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 ce n'est pas le cas.

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 se comparer aux résultats des jointures.

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


1
L'inconvénient est que l'optimiseur ne peut pas utiliser toutes ses astuces de clé étrangère ... ... et que la fonction sera exécutée pour chaque ligne que vous insérez / mettez à jour (donc pas trop agréable pour les ensembles).
jimbobmcgee

1

Désolé, au sens strict du terme, 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 comporte des 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!


cette question concerne le serveur SQL
George Mauer le
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.