¿Puedo tener una clave externa que haga referencia a una columna en una vista en SQL Server?

84

En SQL Server 2008 y dado

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

¿Es posible definir de TableZ(A_or_B_ID, Z_Data)tal manera que la Z.A_or_B_IDcolumna esté restringida a los valores encontrados en ViewC? ¿Se puede hacer esto con una clave externa contra la vista?

bagazo
fuente

Respuestas:

108

No puede hacer referencia a una vista en una clave externa.

Brian Fisher
fuente
37
¿Es esto una limitación del servidor SQL o no es razonable quererlo?
Aaron Anodide
1
@Brian Yo también estaría interesado en saber si esto es una limitación de un servidor SQL o algo irrazonable porque en este punto estoy a punto de emular una vista usando disparadores solo para obtener soporte de FK (aunque estoy usando MySql ).
Trineo
4
Esta es una buena respuesta a estas preguntas de seguimiento - stackoverflow.com/questions/3833150/…
Chris Halcrow
No estoy seguro de cómo es una buena respuesta a esas preguntas ... se trata de un DBMS diferente y dice que las vistas fueron diseñadas para ocultar los detalles del esquema y la conveniencia del usuario. En primer lugar, está bien ... pero esto no sería lo primero en encontrar casos de uso sólidos más allá del diseño inicial. En segundo lugar, no estoy seguro de por qué un FK no haría eso. Una vista puede ser cualquier consulta que ni siquiera tenga que extraer de una tabla, puede ser un montón de constantes unidas ... una clave externa parece bastante sensato en ese caso. Si hay una razón por la que no, espero algo más profundo.
George Mauer
27

En las ediciones anteriores de SQL Server, las claves externas solo eran posibles a través de activadores. Puede imitar una clave externa personalizada creando un activador de inserción que verifica si el valor insertado también aparece en una de las tablas relevantes.

lorin_f
fuente
3
bienvenido a StackOverflow. Encontré valor en su respuesta, ya que proporciona una solución alternativa, pero la respuesta correcta es la aceptada, y la pregunta tiene más de 4 años, por lo que no estoy votando, pero no quería quedarme sin este comentario.
jachguate
16

Si realmente lo necesita A_or_B_IDen TableZ, tiene dos opciones similares:

1) Agregue columnas A_IDy anulables B_IDa la tabla z, A_or_B_IDcree una columna calculada usando ISNULL en estas dos columnas y agregue una restricción CHECK de modo que solo una de A_IDo B_IDno sea nula

2) Agregue una columna TableName a la tabla z, restringida para contener A o B. ahora cree A_IDy B_IDcomo columnas calculadas, que solo son no nulas cuando se nombra su tabla apropiada (usando la expresión CASE). Hazlos persistir también

En ambos casos, ahora tiene columnas A_IDy B_IDque pueden tener claves foráneas apropiadas para las tablas base. La diferencia está en qué columnas se calculan. Además, no necesita TableName en la opción 2 anterior si los dominios de las 2 columnas de ID no se superponen, siempre que su expresión de caso pueda determinar en qué dominio A_or_B_ID cae

(Gracias por comentar por arreglar mi formato)

Damien_The_Unbeliever
fuente
Ponga palabras con guiones bajos en back-ticks: A_or_B_ID
Bill Karwin
Estoy trabajando para agregar algunas funciones a un sistema heredado, y esta es una excelente manera de parchear lo antiguo y lo nuevo. ¡Gracias!
David Gunderson
8

Lo sentimos, no puede FK a una vista en SQL Server.

Jarrett Meyer
fuente
4

Hay otra opción. Trate TableA y TableB como subclases de una nueva tabla llamada TablePrime. Ajuste los valores de ID de TableB para que no coincidan con los valores de ID de TableA. Haga que el ID en TablePrime sea el PK e inserte todos los ID de TableA y TableB (ajustados) en TablePrime. Haga que TableA y TableB tengan relaciones FK en su PK con el mismo ID en TablePrime.

Ahora tiene el patrón de supertipo / subtipo y puede hacer restricciones a TablePrime (cuando desee A o B ) o una de las tablas individuales (cuando solo desee A o solo B ).

Si necesita más detalles por favor pregunte. Hay variaciones que le permitirán asegurarse de que A y B sean mutuamente excluyentes, o tal vez la cosa con la que está trabajando pueda ser ambas al mismo tiempo. Es mejor formalizar eso en los FK si es posible.

ErikE
fuente
2

Es más fácil agregar una restricción que haga referencia a una función definida por el usuario que realiza la verificación por usted, fCheckIfValueExists (columnValue) que devuelve verdadero si el valor existe y falso si no.

La ventaja es que puede recibir múltiples columnas, realizar cálculos con ellas, aceptar valores nulos y aceptar valores que no corresponden con precisión a una clave primaria o comparar con los resultados de las combinaciones.

La desventaja es que el optimizador no puede usar todos sus trucos de clave externa.

Camilo J
fuente
1
La desventaja es que el optimizador no puede usar todos sus trucos de clave externa ... ... y que la función se ejecutará para cada fila que inserte / actualice (por lo que no es demasiado bueno para los conjuntos).
jimbobmcgee
1

Lo sentimos, en el sentido estricto de la palabra, no, no puede establecer claves externas en las vistas. He aquí por qué:

InnoDB es el único motor de almacenamiento integrado para MySQL que presenta claves externas. Cualquier tabla InnoDB se registrará en information_schema.tables con engine = 'InnoDB'.

Las vistas, aunque están registradas en information_schema.tables, tienen un motor de almacenamiento NULL. No hay mecanismos en MySQL para tener claves externas en cualquier tabla que tenga un motor de almacenamiento indefinido.

¡Gracias!

Abdul Aziz Al Basyir
fuente
esta pregunta es sobre el servidor SQL
George Mauer