Я считаю, что название говорит само за себя. Как создать структуру таблицы в PostgreSQL, чтобы установить связь «многие ко многим».
Мой пример:
Product(name, price);
Bill(name, date, Products);
sql
database
postgresql
database-design
many-to-many
Раду Георгиу
источник
источник
Ответы:
Операторы SQL DDL (язык определения данных) могут выглядеть следующим образом:
CREATE TABLE product ( product_id serial PRIMARY KEY -- implicit primary key constraint , product text NOT NULL , price numeric NOT NULL DEFAULT 0 ); CREATE TABLE bill ( bill_id serial PRIMARY KEY , bill text NOT NULL , billdate date NOT NULL DEFAULT CURRENT_DATE ); CREATE TABLE bill_product ( bill_id int REFERENCES bill (bill_id) ON UPDATE CASCADE ON DELETE CASCADE , product_id int REFERENCES product (product_id) ON UPDATE CASCADE , amount numeric NOT NULL DEFAULT 1 , CONSTRAINT bill_product_pkey PRIMARY KEY (bill_id, product_id) -- explicit pk );
Я сделал несколько корректировок:
Отношение n: m обычно реализуется в отдельной таблице -
bill_product
в этом случае.Я добавил
serial
столбцы в качестве суррогатных первичных ключей . В Postgres 10 или новее вместо этого рассмотритеIDENTITY
столбец . Увидеть:Я очень рекомендую это, потому что название продукта вряд ли уникально (не лучший «естественный ключ»). Кроме того, обеспечение уникальности и ссылка на столбец во внешних ключах обычно дешевле для 4-байтовых
integer
(или даже 8-байтовыхbigint
), чем для строки, хранящейся какtext
илиvarchar
.Не используйте имена основных типов данных в
date
качестве идентификаторов . Хотя это возможно, это плохой стиль и приводит к запутанным ошибкам и сообщениям об ошибках. Используйте допустимые идентификаторы в нижнем регистре без кавычек . Никогда не используйте зарезервированные слова и по возможности избегайте двойных кавычек идентификаторов в смешанном регистре.«имя» - плохое имя. Я переименовал столбец таблицы
product
вproduct
(product_name
или аналогичный). Это лучшее соглашение об именах . В противном случае, когда вы присоединитесь пару таблиц в запросе - что вы делаете много в реляционной базе данных - вы в конечном итоге с несколькими столбцами под названием «имя» и должны использовать псевдонимы столбцов , чтобы разобраться в беспорядок. Это бесполезно. Другой распространенный анти-шаблон - это просто «id» в качестве имени столбца.Я не уверен, как
bill
будет называться.bill_id
в этом случае, вероятно, будет достаточно.price
имеет тип данныхnumeric
для хранения дробных чисел точно в том виде, в каком они были введены (тип произвольной точности вместо типа с плавающей запятой). Если вы имеете дело исключительно с целыми числами, сделайте этоinteger
. Например, вы можете сохранить цены в центах .amount
("Products"
В вашем вопросе) переходит в связующей таблицеbill_product
и типа ,numeric
а также. Опять же,integer
если вы имеете дело исключительно с целыми числами.Вы видите , внешние ключи в
bill_product
? Я создал и изменения каскадных:ON UPDATE CASCADE
. Еслиproduct_id
илиbill_id
должен измениться, это изменение каскадно распространяется на все зависимые записи,bill_product
и ничего не прерывается. Это просто ссылки, не имеющие самостоятельного значения.Я также использовал
ON DELETE CASCADE
дляbill_id
: Если счет удаляется, его детали умирают вместе с ним.Не так для продуктов: вы не хотите удалять продукт, который используется в счете. Postgres выдаст ошибку, если вы попытаетесь это сделать.
product
Вместо этого вы должны добавить еще один столбец, чтобы пометить устаревшие строки («мягкое удаление»).Все столбцы в этом базовом примере заканчиваются
NOT NULL
, поэтомуNULL
значения не допускаются. (Да, все столбцы - столбцы первичного ключа определяютсяUNIQUE NOT NULL
автоматически.) Это потому, чтоNULL
значения не имеют смысла ни в одном из столбцов. Облегчает жизнь новичку. Но ты не уйдешь так легко, вы должны понимать ,NULL
обработка в любом случае. Дополнительные столбцы могут разрешатьNULL
значения, функции и объединения могут вводитьNULL
значения в запросы и т. Д.Прочтите главу
CREATE TABLE
в руководстве .Первичные ключи реализуются с уникальным индексом в ключевых столбцах, что позволяет быстро выполнять запросы с условиями в столбцах PK. Однако последовательность ключевых столбцов важна в многоколоночных ключах. Поскольку ПК на
bill_product
на(bill_id, product_id)
в моем примере, вы можете добавить еще один индекс на разproduct_id
или(product_id, bill_id)
если у вас есть запросы ищут данныйproduct_id
и нетbill_id
. Увидеть:Прочтите главу об указателях в руководстве .
источник
bill_product
? Обычно это должно выглядеть так:CREATE INDEX idx_bill_product_id ON booked_rates(bill_id, product_id)
. Это правильно?bill
. Нам нужна сумма на добавленный элементbill_product
.