Я вважаю, що назва сама собою пояснюється. Як створити структуру таблиці в 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
або подібний). Це краща угода про іменування . В іншому випадку, коли ви приєднуєтесь до кількох таблиць у запиті - чого ви багато робите в реляційній базі даних - у вас виходить декілька стовпців з іменем "name" і вам доведеться використовувати псевдоніми стовпців, щоб розібратися в хаосі. Це не корисно. Іншим широко розповсюдженим анти-шаблоном буде просто "id" як назва стовпця.
Я не впевнений, як би називали a bill
. bill_id
цього, мабуть, буде достатньо.
price
має тип даних, numeric
щоб зберігати дробові числа точно так, як їх було введено (довільний тип точності замість типу з плаваючою комою). Якщо ви маєте справу виключно з цілими числами, зробіть це integer
. Наприклад, ви можете заощадити ціни як центи .
amount
( "Products"
В вашому запитанні) переходить в сполучній таблиці bill_product
і типу , numeric
а також. Знову ж таки, integer
якщо ви маєте справу виключно з цілими числами.
Ви бачите зовнішні ключі в bill_product
? Я створив і зміни каскадних: ON UPDATE CASCADE
. Якщо a product_id
або bill_id
має змінитися, зміна каскадується до всіх залежних записів, bill_product
і нічого не ламається. Це лише посилання без власного значення.
Я також використовував ON DELETE CASCADE
для bill_id
: Якщо рахунок видаляється, його реквізити помирають разом з ним.
Для продуктів не так: Ви не хочете видаляти товар, який використовується в рахунку. Postgres видасть помилку, якщо ви спробуєте це. Ви б додали ще один стовпець для product
позначення застарілих рядків ("soft-delete").
Всі стовпці в цьому базовому прикладі виявляються такими NOT NULL
, тому NULL
значення не допускаються. (Так, усі стовпці - стовпці первинного ключа визначаються UNIQUE NOT NULL
автоматично.) Це тому, що NULL
значення не мали б сенсу в жодному із стовпців. Це полегшує життя новачка. Але ви не втечете так легко, вам все одно потрібно зрозуміти NULL
поводження . Додаткові стовпці можуть дозволяти NULL
значення, функції та об’єднання, можуть вводити NULL
значення у запити тощо.
Прочитайте розділ CREATE TABLE
у посібнику .
Первинні ключі реалізовані з унікальним індексом на стовпцях ключів, що робить запити з умовами в стовпцях PK швидкими. Однак послідовність стовпців ключів є релевантною в багатостолбкових ключах. Оскільки у моєму прикладі PK on 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
.