Creo que el título se explica por sí mismo. ¿Cómo se crea la estructura de la tabla en PostgreSQL para establecer una relación de varios a varios?
Mi ejemplo:
Product(name, price);
Bill(name, date, Products);
sql
database
postgresql
database-design
many-to-many
Radu Gheorghiu
fuente
fuente
Respuestas:
Las declaraciones SQL DDL (lenguaje de definición de datos) podrían verse así:
Hice algunos ajustes:
La relación n: m normalmente se implementa mediante una tabla separada,
bill_product
en este caso.Agregué
serial
columnas como claves primarias sustitutas . En Postgres 10 o posterior, considere unaIDENTITY
columna en su lugar. Ver:Lo recomiendo encarecidamente, porque el nombre de un producto no es único (no es una buena "clave natural"). Además, imponer la unicidad y hacer referencia a la columna en claves externas suele ser más económico con 4 bytes
integer
(o incluso 8 bytesbigint
) que con una cadena almacenada comotext
ovarchar
.No utilice nombres de tipos de datos básicos
date
como identificadores . Si bien esto es posible, es de mal estilo y genera errores confusos y mensajes de error. Utilice identificadores legales, en minúsculas y sin comillas . Nunca use palabras reservadas y evite los identificadores de casos mixtos entre comillas dobles si puede."nombre" no es un buen nombre. Cambié el nombre de la columna de la tabla
product
aproduct
(product_name
o similar). Esa es una mejor convención de nomenclatura . De lo contrario, cuando une un par de tablas en una consulta, lo que hace mucho en una base de datos relacional, termina con varias columnas llamadas "nombre" y tiene que usar alias de columna para solucionar el desorden. Eso no ayuda. Otro anti-patrón generalizado sería simplemente "id" como nombre de columna.No estoy seguro de cuál sería el nombre de a
bill
.bill_id
probablemente será suficiente en este caso.price
es de tipo de datosnumeric
para almacenar números fraccionarios exactamente como se ingresaron (tipo de precisión arbitraria en lugar de tipo de coma flotante). Si se ocupa exclusivamente de números enteros, hágalointeger
. Por ejemplo, puede guardar los precios como centavos .El
amount
("Products"
en su pregunta) va a la tabla de enlacebill_product
y también es de tiponumeric
. Nuevamente,integer
si se trata exclusivamente de números enteros.¿Ves las claves externas en
bill_product
? He creado tanto a los cambios en cascada:ON UPDATE CASCADE
. Si unproduct_id
obill_id
debe cambiar, el cambio se aplica en cascada a todas las entradas dependientes debill_product
y no se rompe nada. Esas son solo referencias sin significado propio.También utilicé
ON DELETE CASCADE
parabill_id
: Si se elimina una factura, sus detalles mueren con ella.No es así para los productos: no desea eliminar un producto que se usa en una factura. Postgres arrojará un error si intenta esto. En su lugar, agregaría otra columna para
product
marcar filas obsoletas ("eliminación suave").Todas las columnas de este ejemplo básico terminan siendo
NOT NULL
, porNULL
lo que no se permiten valores. (Sí, todas las columnas; las columnas de clave principal se definenUNIQUE NOT NULL
automáticamente). Esto se debe a que losNULL
valores no tendrían sentido en ninguna de las columnas. Facilita la vida de un principiante. Pero no se escapará tan fácilmente, debe comprender elNULL
manejo de todos modos. Las columnas adicionales pueden permitirNULL
valores, las funciones y las combinaciones pueden introducirNULL
valores en consultas, etc.Lea el capítulo sobre
CREATE TABLE
en el manual .Las claves primarias se implementan con un índice único en las columnas de claves, que agiliza las consultas con condiciones en la (s) columna (s) PK. Sin embargo, la secuencia de columnas clave es relevante en claves multicolumna. Dado que el PK
bill_product
está activado(bill_id, product_id)
en mi ejemplo, es posible que desee agregar otro índice en soloproduct_id
o(product_id, bill_id)
si tiene consultas que buscan un dadoproduct_id
y nobill_id
. Ver:Lea el capítulo sobre índices en el manual .
fuente
bill_product
? Normalmente se debe el siguiente aspecto:CREATE INDEX idx_bill_product_id ON booked_rates(bill_id, product_id)
. ¿Es esto correcto?bill
. Necesitamos la cantidad por artículo agregado enbill_product
.