Чи можу я мати кілька первинних ключів в одній таблиці?
Чи можу я мати кілька первинних ключів в одній таблиці?
Відповіді:
У таблиці може бути складений первинний ключ, який є первинним ключем, зробленим з двох або більше стовпців. Наприклад:
CREATE TABLE userdata (
userid INT,
userdataid INT,
info char(200),
primary key (userid, userdataid)
);
Оновлення: Ось посилання з більш детальним описом складених первинних ключів.
У таблиці може бути кілька ключів-кандидатів. Кожен кандидат-ключ - це стовпчик або набір стовпців, які є УНІКАЛЬНИМИ, взяті разом, а також НЕ NULL. Таким чином, вказуючи значення для всіх стовпців будь-якого ключа-кандидата, достатньо, щоб визначити, що є один рядок, який відповідає критеріям, або взагалі немає рядків.
Ключі кандидата - це фундаментальне поняття в моделі реляційних даних.
Загальна практика, якщо в одній таблиці присутні кілька клавіш, позначати один з ключових кандидатів як основний ключ. Також поширена практика викликати будь-які сторонні ключі до таблиці для посилання на первинний ключ, а не на будь-який інший кандидатський ключ.
Я рекомендую такі практики, але в реляційній моделі немає нічого, що вимагало б вибору первинного ключа серед ключових кандидатів.
Це відповідь як на головне питання, так і на питання @ Кальмі
Який сенс матиме кілька автогенеруючих стовпців?
Цей код нижче має складений первинний ключ. Один з його стовпців автоматично збільшується. Це працюватиме лише в MyISAM. InnoDB генерує помилку " ПОМИЛКА 1075 (42000): Неправильне визначення таблиці; може бути лише один стовпець авто, і він повинен бути визначений як ключ ".
DROP TABLE IF EXISTS `test`.`animals`;
CREATE TABLE `test`.`animals` (
`grp` char(30) NOT NULL,
`id` mediumint(9) NOT NULL AUTO_INCREMENT,
`name` char(30) NOT NULL,
PRIMARY KEY (`grp`,`id`)
) ENGINE=MyISAM;
INSERT INTO animals (grp,name) VALUES
('mammal','dog'),('mammal','cat'),
('bird','penguin'),('fish','lax'),('mammal','whale'),
('bird','ostrich');
SELECT * FROM animals ORDER BY grp,id;
Which returns:
+--------+----+---------+
| grp | id | name |
+--------+----+---------+
| fish | 1 | lax |
| mammal | 1 | dog |
| mammal | 2 | cat |
| mammal | 3 | whale |
| bird | 1 | penguin |
| bird | 2 | ostrich |
+--------+----+---------+
(Вивчали їх багато)
Ключі кандидата - Мінімальна комбінація стовпців, необхідна для унікального визначення рядка таблиці.
Складені ключі - 2 і більше стовпців.
Джерела:
https://en.wikipedia.org/wiki/Superkey
https://en.wikipedia.org/wiki/Candidate_key
https://en.wikipedia.org/wiki/Primary_key
https://en.wikipedia.org / wiki / Compound_key
Як зазначають інші, можна мати багатоколонкові первинні ключі. Слід зазначити, що якщо у вас є деякі функціональні залежності , які не вводяться ключем, вам слід розглянути питання про нормалізацію свого відношення.
Приклад:
Person(id, name, email, street, zip_code, area)
Можлива функціональна залежність між. id -> name,email, street, zip_code and area
Але часто а zip_code
асоціюється з area
а, тому між ними існує внутрішня функціональна залежність zip_code -> area
.
Таким чином, можна розглянути розділення його на іншу таблицю:
Person(id, name, email, street, zip_code)
Area(zip_code, name)
Так, щоб він відповідав третій нормальній формі .
Первинний ключ - це дуже невдале позначення через конотацію "Первинного" та підсвідомої асоціації внаслідок логічної моделі. Таким чином я уникаю його використання. Натомість я посилаюся на сурогатний ключ фізичної моделі та природний ключ (і) логічної моделі.
Важливо, щоб логічна модель для кожного суб'єкта господарювання мала щонайменше один набір "бізнес-атрибутів", які містять ключ для сутності. Бойс, Кодд, Дата та ін називають їх у реляційній моделі як ключі кандидата. Коли ми потім будуємо таблиці для цих організацій, їхні ключі-кандидати стають природними ключами в цих таблицях. Лише за допомогою цих природних ключів користувачі можуть однозначно ідентифікувати рядки в таблицях; оскільки сурогатні ключі завжди повинні ховатися від користувачів. Це тому, що сурогатні ключі не мають ділового значення.
Однак фізична модель для наших таблиць у багатьох випадках буде неефективною без сурогатного ключа. Нагадаємо, що непокриті стовпці для некластеризованого індексу можна знайти (загалом) лише за допомогою ключа пошуку в кластерному індексі (ігнорувати таблиці, реалізовані як купи на мить). Коли наші доступні природні ключі є широкими, це (1) розширює ширину наших некластеризованих вузлів листків, збільшуючи вимоги до зберігання та читати доступ для пошуку та сканування цього некластеризованого індексу; і (2) зменшує відмітку від нашого кластеризованого індексу, збільшуючи висоту індексу та розмір індексу, знову збільшуючи вимоги до читання та зберігання для наших кластерних індексів; та (3) збільшує вимоги до кешу для наших кластерних індексів. переслідування інших індексів та даних із кешу.
Ось тут невеликий сурогатний ключ, призначений RDBMS як "первинний ключ", виявляється корисним. Якщо встановлено як кластеризаційний ключ, щоб використовувати його для пошуку ключів у кластерний індекс з некластеризованих індексів та пошуку зовнішніх ключів із пов’язаних таблиць, всі ці недоліки зникають. Наші кластеризовані вентилятори індексу знову збільшуються, щоб зменшити висоту та розмір індексів кластера, зменшити навантаження кешу для наших кластерних індексів, зменшити зчитування під час доступу до даних через будь-який механізм (будь то сканування індексу, пошук індексу, пошук некластеризованих ключів або пошук зовнішнього ключа) та зменшити вимоги до зберігання як кластерних, так і некластеризованих індексів наших таблиць.
Зауважте, що ці переваги виникають лише тоді, коли сурогатний ключ є і малим, і кластерним ключем. Якщо GUID використовується як ключ кластеризації, ситуація часто буде гіршою, ніж якби був використаний найменший доступний природний ключ. Якщо таблиця організована як купа, то для пошуку ключів буде використовуватися 8-байтовий (куча) RowID, який кращий за 16-байтовий GUID, але менш ефективний, ніж 4-байтове ціле число.
Якщо GUID потрібно використовувати через обмеження бізнесу, то пошуки кращого кластеризаційного ключа варто. Якщо, наприклад, невеликий ідентифікатор сайту та 4-байтовий "номер послідовності сайту" є можливим, то такий дизайн може дати кращі показники, ніж GUID як сурогатний ключ.
Якщо наслідки купи (можливо, приєднання хешу) дають перевагу сховищу, то витрати на ширший кластеризаційний ключ необхідно збалансувати в аналізі компромісу.
Розглянемо цей приклад ::
ALTER TABLE Persons
ADD CONSTRAINT pk_PersonID PRIMARY KEY (P_Id,LastName)
де кортеж " (P_Id, LastName) " вимагає обмеження унікальності, і може бути тривалим Unicode LastName плюс 4-байтовим цілим числом, було б бажано (1) декларативно застосувати це обмеження як " ДОДАТИ КОНСТРУКТУВАННЯ pk_PersonID UNIQUE NONCLUSTERED (P_Id , LastName) "та (2) окремо оголошують маленький сурогатний ключ" первинним ключем "кластерного індексу. Варто зазначити, що Anita, можливо, бажає лише додати LastName до цього обмеження, щоб зробити це закритим полем, яке є непотрібним у кластерному індексі, оскільки всі поля охоплені ним.
Можливість SQL Server призначити Первинний ключ некластеризованим - це прикрою історичною обставиною, пов’язаною зі співвідношенням значення "бажаний природний або кандидатський ключ" (з логічної моделі) зі значенням "ключ пошуку в сховищі" з фізичного Модель. Я розумію, що спочатку SYBASE SQL Server завжди використовував 4-байтовий RowID, чи то в купу, так і в кластерний індекс, як "ключ пошуку в сховищі" з фізичної моделі.
Деякі люди використовують термін "первинний ключ", щоб означати саме цілий стовпець, який отримує свої значення, породжені деяким автоматичним механізмом. Наприклад, AUTO_INCREMENT
в MySQL або IDENTITY
в Microsoft SQL Server. Ви використовуєте первинний ключ у цьому сенсі?
Якщо так, відповідь залежить від бренду бази даних, яку ви використовуєте. У MySQL цього не можна зробити, ви отримуєте помилку:
mysql> create table foo (
id int primary key auto_increment,
id2 int auto_increment
);
ERROR 1075 (42000): Incorrect table definition;
there can be only one auto column and it must be defined as a key
У деяких інших брендах бази даних ви можете визначити більше одного стовпця, що автоматично генерує, у таблиці.
Мати два первинні ключі одночасно, неможливо. Але (якщо припустити, що ви не зіпсували корпус складеним ключем), можливо, вам може знадобитися зробити один атрибут унікальним.
CREATE t1(
c1 int NOT NULL,
c2 int NOT NULL UNIQUE,
...,
PRIMARY KEY (c1)
);
Однак зауважте, що у реляційній базі даних «супер ключ» - це підмножина атрибутів, яка однозначно ідентифікує кортеж чи рядок у таблиці. "Ключ" - це "супер ключ", який має додаткову властивість, яка видаляє будь-який атрибут з ключа, робить цей ключ більше не "супер ключем" (або просто "ключ" - це мінімальний супер ключ). Якщо ключів більше, усі вони є ключами-кандидатами. Ми вибираємо один з ключів-кандидатів як основний ключ. Ось чому говорити про декілька первинних ключів для одного відношення чи таблиці - це конфлікт.
Первинний ключ - це ключ, який однозначно ідентифікує запис і використовується у всіх індексах. Ось чому ви не можете мати більше одного. Це також загалом ключ, який використовується при приєднанні до дочірніх таблиць, але це не є вимогою. Справжня мета ПК - переконатися, що щось дозволяє вам однозначно ідентифікувати запис, щоб зміни даних впливали на правильний запис і таким чином можна було створювати індекси.
Однак ви можете помістити кілька полів в один первинний ключ (складений ПК). Це зробить ваші приєднання повільнішими (особливо якщо вони є більшими полями рядкових рядків), а ваші індекси збільшаться, але це може усунути необхідність приєднання до деяких дочірніх таблиць, тому що стосується продуктивності та дизайну, прийміть це у випадку, підстава справи. Коли ви це робите, кожне поле саме по собі не є унікальним, але їх поєднання є. Якщо одне або кілька полів у складеному ключі також має бути унікальним, то вам потрібен унікальний індекс на ньому. Імовірно, якщо одне поле є унікальним, це кращий кандидат на ПК.
Зараз часом у вас є більше одного кандидата на ПК. У цьому випадку ви вибираєте ключ як ПК або використовуєте сурогатний ключ (я особисто віддаю перевагу сурогатним ключам для цього випадку). І (це важливо!) Ви додаєте унікальні індекси до кожного з кандидатських ключів, які не були обрані як ПК. Якщо дані мають бути унікальними, йому потрібен унікальний індекс, чи це ПК чи ні. Це питання цілісності даних. (Зверніть увагу, це також справедливо, коли ви використовуєте сурогатний ключ; люди потрапляють у проблеми із сурогатними ключами, оскільки вони забувають створювати унікальні індекси на кандидатських ключах.)
Інколи трапляються випадки, коли потрібно більше одного сурогатного ключа (як правило, ПК, якщо у вас є). У цьому випадку те, що ви хочете, не більше ПК, це більше полів з автогенерованими ключами. Більшість БД цього не дозволяють, але є способи їх обійти. Спочатку подумайте, чи може друге поле обчислюватися на основі першого автогенерованого ключа (наприклад, Field1 * -1) або, можливо, потреба у другому автогенерованому ключі дійсно означає, що вам слід створити пов’язану таблицю. Пов’язані таблиці можуть бути у взаємозв'язку один на один. Ви б застосували це, додавши ПК з батьківської таблиці до дочірньої таблиці, а потім додавши до таблиці нове автоматично сформоване поле, а потім усі поля, які підходять для цієї таблиці. Потім виберіть одну з двох клавіш як ПК, а іншу поставте унікальний індекс (автогенероване поле не повинно бути ПК). І обов’язково додайте FK до поля, яке знаходиться в батьківській таблиці. Загалом, якщо у вас немає додаткових полів для дочірньої таблиці, вам потрібно вивчити, чому ви вважаєте, що вам потрібні два автогенеровані поля.
Хороші технічні відповіді були надані краще, ніж я можу зробити. Я лише можу додати до цієї теми:
Якщо ви хочете чогось не дозволеного / прийнятного, це вагомий привід зробити крок назад.
Сподіваюся, що це допоможе комусь.
Так, це можливо в SQL, але ми не можемо встановити більше одного первинного ключа в MsAccess. Тоді я не знаю про інші бази даних.
CREATE TABLE CHAPTER (
BOOK_ISBN VARCHAR(50) NOT NULL,
IDX INT NOT NULL,
TITLE VARCHAR(100) NOT NULL,
NUM_OF_PAGES INT,
PRIMARY KEY (BOOK_ISBN, IDX)
);