Я вважаю, що назва сама собою пояснюється. Як створити структуру таблиці в 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.