12
votes

Comment imiter le syndicat Tagged dans une base de données?

Quelle est la meilleure façon d'émuler Tagged Union dans des bases de données? Je parle de quelque chose comme ceci: xxx

où le véhicule_id serait ID dans la table de voitures ou la table de l'automobile, et sachez que.

(supposons que le moteur et Les tables de voiture n'ont rien de commun0


0 commentaires

4 Réponses :


6
votes
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
  ...
)

3 commentaires

Cela faciliterait la vie si vous avez défini véhicule.vehicle_id comme clé principale afin de ne pas avoir à faire référence à une clé composite et que vous avez des colonnes de type et d'identité à l'aide d'une contrainte unique.


@OMG Ponies: Avec cette mise en page, vous n'avez pas besoin de référencer véhicule du tout. Vous pouvez simplement rejoindre voitures ou motocycles , en fonction du type . Véhicule Ici ne sert que de policier les relations.


Avec cette méthode, existe-t-il un moyen de garantir qu'il n'y aura pas de "orpheline" des véhicules qui n'ont pas une ligne correspondante dans voiture ou motocyclycle ?



10
votes

Certaines personnes utilisent une conception appelée associations polymorphes pour le faire, permettant véhicule_id code> contenir une valeur qui existe dans voiture code> ou Moteur code> . Ajoutez ensuite un véhicule_type code> qui nomme la table que la ligne donnée dans t1 code> références.

Le problème est que vous ne pouvez pas déclarer une vraie contrainte de clé étrangère SQL si vous faites cela. Il n'y a pas de support dans SQL pour une clé étrangère comportant plusieurs cibles de référence. Il y a aussi d'autres problèmes, mais le manque d'intégrité référentielle est déjà un pot-casseur. P>

Un meilleur design consiste à emprunter un concept de la conception de OO d'un Superype em> de voiture code> et Moteur CODE>: P>

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)
  ...
);


2 commentaires

La clé de substitution pour identifiable est seulement bonne quand il y a des attributs dans identifiables que la requête doit sélectionner. Si identifiable ne sert à appliquer les contraintes, à l'aide d'une clé composite permettra de s'en débarrasser dans les requêtes sur les questions.


J'ai monté et j'ai utilisé l'approche "Common Superype", et l'a utilisé avec succès dans les principaux projets de migration / réaménagement du système. (Gouvernement NZ, Spot25 pour la MEO)



3
votes

Je pense que vous pouvez modéliser une telle référence en utilisant héritage de table dans PostgreSQL .

Si vous avez vraiment besoin de savoir où une ligne vient dans une requête, vous pouvez utiliser une simple syndicat toutes les déclarations telles que (cette possibilité n'a rien à voir avec la table héritage): < Pré> xxx


0 commentaires

3
votes

Je pense que la solution la moins achalandée est d'utiliser contrainte code> et vérifier code>.

Par exemple, considérez cette adt dans HASKELLL: P>

CREATE TABLE shape (        
  type ENUM('circle', 'rectangle') NOT NULL,
  radius FLOAT,             
  width FLOAT,              
  height FLOAT,             
  CONSTRAINT constraint_circle CHECK 
    (type <> 'circle' OR radius IS NOT NULL),
  CONSTRAINT constraint_rectangle CHECK 
    (type <> 'rectangle' OR (width IS NOT NULL AND height IS NOT NULL))
);                                      
                                        
INSERT INTO shape(type, radius, width, height)
  VALUES ('circle', 1, NULL, NULL); -- ok
                                                                                                                    
INSERT INTO shape(type, radius, width, height)
  VALUES ('circle', NULL, 1, NULL); -- error, constraint_circle violated


1 commentaires

FWIW: Dire type <> x ou y est en réalité équivalente à l'implication: type = x => y . Une autre expression équivalente (sans doute à digérer) serait non (type = x et non y) . C'est à dire. Il est pas autorisé à être un cercle et non pour avoir un rayon. Votre version est transformée en une forme plus compacte à l'aide de la législation de De Morgan.