J'ai rencontré des problèmes pour modéliser un schéma électrique en SQL. La structure que j'aimerais capturer est
part ←────────── pin
↑ ↑
part_inst ←───── pin_inst
où "inst" est l'abréviation de "instance".
Par exemple, je pourrais avoir un part
ampli-op LM358 avec pin
s 1OUT, 1IN-, 1IN +, GND, 2IN +, 2IN-, 2OUT et V CC . Je pourrais alors placer cette partie sur un schéma, créant un part_inst
et 8
pin_inst
s.
Ignorant les champs de données, ma tentative initiale de schéma était
create table parts (
part_id bigserial primary key
);
create table pins (
pin_id bigserial primary key,
part_id bigint not null references parts
);
create table part_insts (
part_inst_id bigserial primary key,
part_id bigint not null references parts
);
create table pin_insts (
pin_inst_id bigserial primary key,
part_inst_id bigint not null references part_insts,
pin_id bigint not null references pins
);
Le principal problème avec ce schéma est qu'un pin_inst
peut être lié à un part_inst
avec part_id=1
mais qu'il pin
a part_id=2
.
Je voudrais éviter ce problème au niveau de la base de données plutôt qu'au niveau de l'application. J'ai donc modifié mes clés primaires pour appliquer cela. J'ai marqué les lignes modifiées avec --
.
create table parts (
part_id bigserial primary key
);
create table pins (
pin_id bigserial, --
part_id bigint not null references parts,
primary key (pin_id, part_id) --
);
create table part_insts (
part_inst_id bigserial, --
part_id bigint not null references parts,
primary key (part_inst_id, part_id) --
);
create table pin_insts (
pin_inst_id bigserial primary key,
part_inst_id bigint not null, --
pin_id bigint not null, --
part_id bigint not null references parts, --
foreign key (part_inst_id, part_id) references part_insts, --
foreign key (pin_id, part_id) references pins --
);
Mon reproche avec cette méthode est qu'elle pollue les clés primaires: partout où je me réfère à un part_inst
, je dois garder une trace à la fois du
part_inst_id
et du part_id
. Existe-t-il un autre moyen de faire respecter la contrainte
pin_inst.part_inst.part_id = pin_inst.pin.part_id
sans être trop verbeux?
la source
pin_inst_id
qui est une redondance. Vous pouvez utiliser la(part_inst_id, part_id, pin_id)
clé primaire.Réponses:
Solution minimale
Une solution radicale pourrait être de supprimer
pin_inst
complètement:Rien dans votre question ne suggère que vous avez réellement besoin de la table redondante. Pour les
pin
s associés à apart_inst
, regardez lespin
s des associéspart
.Cela simplifierait le code pour:
Mais votre commentaire indiquait clairement que nous n'allons pas nous en sortir avec ça ...
Alternative si
pin_inst
nécessaireInclure
part_id
comme vous l'avez fait est la solution la plus simple avec des contraintes de clé étrangère. Vous ne pouvez pas référencer une table "à deux tables" avec des contraintes de clé étrangère .Mais vous pouvez au moins vous débrouiller sans «polluer» les clés primaires. Ajoutez des
UNIQUE
contraintes .Je mets d'
part_id
abord dans les contraintes uniques. Cela n'est pas pertinent pour l'intégrité référentielle, mais c'est important pour les performances. Les clés primaires implémentent déjà des index pour les colonnes pk. Il est préférable d'avoir l' autre colonne en premier dans les index multicolonnes implémentant les contraintes uniques. Détails sous ces questions connexes:Questions connexes sur SO:
Alternative avec déclencheurs
Vous pouvez recourir à des fonctions de déclencheurs, qui sont plus flexibles, mais un peu plus compliquées et sujettes aux erreurs et un peu moins strictes. L'avantage: vous pouvez vous en passer
part_inst.part_id
etpin.part_id
...la source
pin_insts
, mais je les ai omises dans un souci de lisibilité ("Ignorer les champs de données, [...]"). Par exemple, apin_inst
peut être marqué comme entrée ou sortie.