Me encontré con algunos problemas al modelar un esquema eléctrico en SQL. La estructura que me gustaría capturar es
part ←────────── pin
↑ ↑
part_inst ←───── pin_inst
donde "inst" es la abreviatura de "instancia".
Por ejemplo, podría tener como part
amplificador operacional pin
LM358 con s 1OUT, 1IN-, 1IN +, GND, 2IN +, 2IN-, 2OUT y V CC . Entonces podría colocar esta parte en un esquema, creando ay part_inst
8
pin_inst
s.
Ignorando los campos de datos, mi intento inicial de un esquema fue
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
);
El principal problema con este esquema es que a pin_inst
podría estar vinculado a un part_inst
con part_id=1
pero pin
tiene part_id=2
.
Me gustaría evitar este problema en el nivel de la base de datos en lugar del nivel de la aplicación. Entonces, modifiqué mis claves principales para hacer cumplir eso. Marqué las líneas cambiadas con --
.
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 --
);
Mi queja con este método es que contamina las claves principales: en todas partes me refiero a part_inst
, necesito hacer un seguimiento tanto de la
part_inst_id
como de la part_id
. ¿Hay alguna otra manera de hacer cumplir la restricción
pin_inst.part_inst.part_id = pin_inst.pin.part_id
sin ser demasiado detallado?
pin_inst_id
redundancia. Puede usar(part_inst_id, part_id, pin_id)
como clave principal.Respuestas:
Solución mínima
Una solución radical podría ser eliminar por
pin_inst
completo:No hay nada en su pregunta que sugiera que realmente necesita la tabla redundante. Para los
pin
s asociados a apart_inst
, mire lospin
s de los asociadospart
.Eso simplificaría el código para:
Pero su comentario dejó en claro que no nos saldremos con la suya ...
Alternativa si
pin_inst
es necesariaIncluir
part_id
como lo hizo es la solución más simple con restricciones de clave externa. No puede hacer referencia a una tabla "a dos tablas de distancia" con restricciones de clave externa .Pero al menos puede hacerlo sin "contaminar" las claves primarias. Agregar
UNIQUE
restricciones .Puse
part_id
primero en las restricciones únicas. Eso es irrelevante para la integridad referencial, pero es importante para el desempeño. Las claves principales ya implementan índices para las columnas pk. Es mejor tener la otra columna primero en los índices de varias columnas que implementan las restricciones únicas. Detalles bajo estas preguntas relacionadas:Preguntas relacionadas sobre SO:
Alternativa con desencadenantes
Podría recurrir a funciones de activación, que son más flexibles, pero un poco más complicadas y propensas a errores y un poco menos estrictas. El beneficio: podría prescindir
part_inst.part_id
ypin.part_id
...fuente
pin_insts
, pero las omití en interés de la legibilidad ("Ignorando los campos de datos, [...]"). Por ejemplo, apin_inst
puede marcarse como entrada o salida.