Я считаю, что название говорит само за себя. Как создать структуру таблицы в 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.