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 partamplificador operacional pinLM358 con s 1OUT, 1IN-, 1IN +, GND, 2IN +, 2IN-, 2OUT y V CC . Entonces podría colocar esta parte en un esquema, creando ay part_inst8
pin_insts.
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_instpodría estar vinculado a un part_instcon part_id=1pero pintiene 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_idcomo de la part_id. ¿Hay alguna otra manera de hacer cumplir la restricción
pin_inst.part_inst.part_id = pin_inst.pin.part_idsin ser demasiado detallado?

pin_inst_idredundancia. 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_instcompleto:No hay nada en su pregunta que sugiera que realmente necesita la tabla redundante. Para los
pins asociados a apart_inst, mire lospins 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_instes necesariaIncluir
part_idcomo 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
UNIQUErestricciones .Puse
part_idprimero 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_idypin.part_id...fuente
pin_insts, pero las omití en interés de la legibilidad ("Ignorando los campos de datos, [...]"). Por ejemplo, apin_instpuede marcarse como entrada o salida.