Me encuentro con una situación en la base de datos con bastante frecuencia en la que una tabla determinada puede FK a una de varias tablas principales diferentes. He visto dos soluciones para el problema, pero ninguna es personalmente satisfactoria. Tengo curiosidad por saber qué otros patrones has visto por ahí. Hay una mejor manera de hacerlo?
Un ejemplo controlado
Digamos que mi sistema tiene Alerts
. Se pueden recibir alertas para una variedad de objetos: clientes, noticias y productos. Una alerta dada puede ser para un solo artículo. Por alguna razón, los Clientes, los Artículos y los Productos se mueven rápidamente (o se localizan), por lo que el texto / datos necesarios no se pueden incluir en Alertas al crear una Alerta. Dada esta configuración, he visto dos soluciones.
Nota: A continuación, DDL es para SQL Server, pero mi pregunta debería ser aplicable a cualquier DBMS.
Solución 1 - Múltiples teclas anulables
En esta solución, la tabla que enlaza con una de muchas tablas tiene múltiples columnas FK (por razones de brevedad, el siguiente DDL no muestra la creación de FK). LO BUENO : en esta solución es bueno que tenga claves foráneas. La nulidad opcional de los FK hace que sea conveniente y relativamente fácil agregar datos precisos. LA MALA consulta no es excelente porque requiere N NEFT JOINS o N UNION para obtener los datos asociados. En SQL Server, específicamente las uniones izquierdas impiden la creación de una vista indizada.
CREATE TABLE Product (
ProductID int identity(1,1) not null,
CreateUTC datetime2(7) not null,
Name varchar(100) not null
CONSTRAINT PK_Product Primary Key CLUSTERED (ProductID)
)
CREATE TABLE Customer (
CustomerID int identity(1,1) not null,
CreateUTC datetime2(7) not null,
Name varchar(100) not null
CONSTRAINT PK_Customer Primary Key CLUSTERED (CustomerID)
)
CREATE TABLE News (
NewsID int identity(1,1) not null,
CreateUTC datetime2(7) not null,
Name varchar(100) not null
CONSTRAINT PK_News Primary Key CLUSTERED (NewsID)
)
CREATE TABLE Alert (
AlertID int identity(1,1) not null,
CreateUTC datetime2(7) not null,
ProductID int null,
NewsID int null,
CustomerID int null,
CONSTRAINT PK_Alert Primary Key CLUSTERED (AlertID)
)
ALTER TABLE Alert WITH CHECK ADD CONSTRAINT CK_OnlyOneFKAllowed
CHECK (
(ProductID is not null AND NewsID is null and CustomerID is null) OR
(ProductID is null AND NewsID is not null and CustomerID is null) OR
(ProductID is null AND NewsID is null and CustomerID is not null)
)
Solución 2: un FK en cada tabla principal
En esta solución, cada tabla 'principal' tiene un FK en la tabla de alerta. Facilita la recuperación de alertas asociadas con un padre. En el lado negativo, no hay una cadena real desde la Alerta a quién se hace referencia. Además, el modelo de datos permite alertas huérfanas, donde una alerta no está asociada con un producto, noticia o cliente. Nuevamente, múltiples IZQUIERDAS SE UNEN para descubrir la asociación.
CREATE TABLE Product (
ProductID int identity(1,1) not null,
CreateUTC datetime2(7) not null,
Name varchar(100) not null
AlertID int null,
CONSTRAINT PK_Product Primary Key CLUSTERED (ProductID)
)
CREATE TABLE Customer (
CustomerID int identity(1,1) not null,
CreateUTC datetime2(7) not null,
Name varchar(100) not null
AlertID int null,
CONSTRAINT PK_Customer Primary Key CLUSTERED (CustomerID)
)
CREATE TABLE News (
NewsID int identity(1,1) not null,
CreateUTC datetime2(7) not null,
Name varchar(100) not null
AlertID int null,
CONSTRAINT PK_News Primary Key CLUSTERED (NewsID)
)
CREATE TABLE Alert (
AlertID int identity(1,1) not null,
CreateUTC datetime2(7) not null,
CONSTRAINT PK_Alert Primary Key CLUSTERED (AlertID)
)
¿Es esto solo vida en una base de datos de relaciones? ¿Hay soluciones alternativas que te hayan resultado más satisfactorias?
fuente
Alertable
. Eso tiene sentido?Respuestas:
Entiendo que la segunda solución no es aplicable, ya que no ofrece una relación (objeto) a muchos (alerta).
Está atascado con solo dos soluciones debido al estricto cumplimiento de 3NF.
Diseñaría un esquema de acoplamiento menor:
O, si la relación de integridad es obligatoria, podría diseñar:
De todas formas...
Tres soluciones válidas más otra a tener en cuenta para muchas relaciones (objetos) a uno (alerta) ...
Estos presentados, ¿cuál es la moraleja?
Difieren sutilmente y pesan lo mismo en los criterios:
Por lo tanto, elija el más cómodo para usted.
fuente
He usado tablas de unión mantenidas por disparador. la solución funciona bastante bien como último recurso si no es posible o deseable refactorizar la base de datos. La idea es que tiene una tabla que está ahí solo para manejar los problemas de RI, y todo DRI va en contra de ella.
fuente