Как реализовать отношение "многие ко многим" в PostgreSQL?
Я считаю, что название говорит само за себя. Как создать структуру таблиц в PostgreSQL, чтобы создать отношение "многие ко многим".
мой пример:
Product(name, price);
Bill(name, date, Products);
1 ответов
операторы 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
колонок суррогатные первичные ключи. Я очень рекомендую это, потому что название продукта вряд ли уникальный. Кроме того, обеспечение уникальности и ссылки на столбец во внешних ключах намного дешевле с 4-байтовымinteger
чем со строкой, хранящейся вtext
илиvarchar
.
В Postgres 10 или более поздней версии рассмотримIDENTITY
колонки вместо. Подробности: не используйте имена основных типов данных, таких как
date
as коды. Хотя это возможно, это плохой стиль и приводит к путанице ошибок и сообщений об ошибках. Использовать юридические, строчные, без кавычек идентификаторы. Никогда не используйте зарезервированные слова и избегайте двойных кавычек идентификаторов смешанных случаев, если можете.name
не очень хорошее имя. Я переименовал таблицыproduct
наproduct
. Это лучше соглашение об именах. В противном случае, когда вы объединить несколько таблиц в запросе - что вы делаете большое в реляционной базе данных-вы получаете несколько столбцов с именемname
и нужно использовать псевдонимы столбцов, чтобы разобраться в беспорядке. Это не поможет. Другой широко распространенный анти-шаблон будет простоid
как имя столбца.
Я не уверен, что названиеbill
будет. Может быть!--15--> может быть имя в этом случае.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
: если вы удалите счет, детали будут удалены вместе с ним.
Не так для продуктов: вы не хотите удалять продукт, который используется в счете. Сервер выдаст ошибку, если попробуй это. Вы добавите еще один столбец в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
. Подробности: читать глава по индексам в руководстве.