2009-11-13 13 views
11

¿Cuál es la mejor manera de emular Tagged union en bases de datos? Estoy hablando de algo como esto:¿Cómo emular la unión etiquetada en una base de datos?

create table t1 { 
    vehicle_id INTEGER NOT NULL REFERENCES car(id) OR motor(id) -- not valid 
    ... 
} 

donde vehicle_id sería id en la tabla coche o tabla de motores, y sería saber qué.

(se supone que el motor y el coche tablas no tienen nada en common0

Respuesta

9

Algunas personas utilizan un diseño llamado Asociaciones polimórficos hacer esto, lo que permite vehicle_id para contener un valor que existe ya sea en car o motor tablas. A continuación, agregue un vehicle_type que nombra la tabla que la fila dada en t1 referencias.

El problema es que no puede declarar una restricción de clave externa de SQL real si hace esto. No hay soporte en SQL para una clave externa que tiene multiplicar e objetivos de referencia. También hay otros problemas, pero la falta de integridad referencial ya es un factor decisivo.

Un diseño mejor es pedir prestado un concepto de diseño orientado a objetos de un supertipo común de ambos car y motor:

CREATE TABLE Identifiable (
id SERIAL PRIMARY KEY 
); 

A continuación, hacer referencia t1 esta tabla supertipo:

CREATE TABLE t1 (
    vehicle_id INTEGER NOT NULL, 
    FOREIGN KEY (vehicle_id) REFERENCES identifiable(id) 
    ... 
); 

Y también hace que los subtipos hagan referencia a su supertipo principal. Tenga en cuenta que la clave principal de los subtipos es no autoincrementando. El supertipo principal se encarga de asignar un nuevo valor de identificación, y los hijos solo hacen referencia a ese valor.

CREATE TABLE car (
    id INTEGER NOT NULL, 
    FOREIGN KEY (id) REFERENCES identifiable(id) 
    ... 
); 

CREATE TABLE motor (
    id INTEGER NOT NULL, 
    FOREIGN KEY (id) REFERENCES identifiable(id) 
    ... 
); 

Ahora puede tener verdadera integridad referencial, pero también admite múltiples tablas de subtipos con sus propios atributos.


La respuesta por @Quassnoi muestra también un método para hacer cumplir subtipos disjuntos. Es decir, desea evitar que car y motor hagan referencia a la misma fila en su tabla de supertipo principal. Cuando hago esto, utilizo una clave primaria de una sola columna para Identifiable.id pero también declaro una clave UNIQUE sobre Identifiable.(id, type). Las claves externas en car y motor pueden hacer referencia a la clave única de dos columnas en lugar de a la clave principal.

+0

La clave sustituta para "identificable" solo es válida cuando hay atributos en "identificable" que la consulta debe seleccionar. Si 'identificable' solo sirve para hacer cumplir las restricciones, el uso de una clave compuesta permitirá deshacerse de él en las consultas por completo. – Quassnoi

+1

He creado y utilizado el enfoque de "supertipo común" y lo utilicé con éxito en proyectos importantes de migración/reurbanización de sistemas. (Gobierno de Nueva Zelanda, SPOT25 para MoE) –

5
CREATE TABLE vehicle (type INT NOT NULL, id INT NOT NULL, 
      PRIMARY KEY (type, id) 
) 

CREATE TABLE car (type INT NOT NULL DEFAULT 1, id INT NOT NULL PRIMARY KEY, 
      CHECK(type = 1), 
      FOREIGN KEY (type, id) REFERENCES vehicle 
) 

CREATE TABLE motorcycle (type INT NOT NULL DEFAULT 2, id INT NOT NULL PRIMARY KEY, 
      CHECK(type = 2), 
      FOREIGN KEY (type, id) REFERENCES vehicle 
) 

CREATE TABLE t1 (
    ... 
    vehicle_type INT NOT NULL, 
    vehicle_id INT NOT NULL, 
    FOREIGN KEY (vehicle_type, vehicle_id) REFERENCES vehicle 
    ... 
) 
+0

Sería hacer es más fácil si definió 'VEHICLE.VEHICLE_ID' como clave principal, por lo que no tiene que hacer referencia a una clave compuesta, y tiene columnas de tipo & id que utilizan una restricción única. –

+0

'@OMG Ponies:' Con este diseño, no necesita hacer referencia a 'vehicle' en absoluto.Simplemente puede unirse a 'cars' o' motocicletes', según el 'tipo'. 'vehículo' aquí solo sirve para controlar las relaciones. – Quassnoi

+0

Con este método, ¿hay alguna forma de garantizar que no habrá vehículos "huérfanos" que no tengan una fila correspondiente en "automóvil" o "motocicleta"? –

3

Creo que podría modelar tal referencia usando table inheritance in PostgreSQL.

Si realmente necesita saber dónde una fila viene en una consulta, se puede utilizar una simple unión TODA LA DECLARACIÓN como (esta posibilidad no tiene nada que ver con la herencia de tablas):

SELECT car.*, 'car' table_name 
UNION ALL 
SELECT motor.*, 'motor' table_name 
Cuestiones relacionadas