Я считаю, что название говорит само за себя. Как создать структуру таблицы в PostgreSQL, чтобы установить связь «многие ко многим».
Мой пример:
Product(name, price);
Bill(name, date, Products);
Я считаю, что название говорит само за себя. Как создать структуру таблицы в PostgreSQL, чтобы установить связь «многие ко многим».
Мой пример:
Product(name, price);
Bill(name, date, Products);
Ответы:
Операторы 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
.