Могу ли я иметь несколько первичных ключей в одной таблице?

Могу ли я иметь несколько первичных ключей в одной таблице?

Ответ 1

Таблица может иметь составной первичный ключ, который является первичным ключом, состоящим из двух или более столбцов. Например:

CREATE TABLE userdata (
  userid INT,
  userdataid INT,
  info char(200),
  primary key (userid, userdataid)
);

Обновление: Вот ссылка с более подробным описанием составных первичных ключей.

Ответ 2

У вас может быть только один первичный ключ, но вы можете иметь несколько столбцов в своем первичном ключе.

Вы также можете иметь уникальные индексы в своей таблице, которые будут немного похожи на первичный ключ, поскольку они будут применять уникальные значения и ускорят запрос этих значений.

Ответ 3

В таблице может быть несколько ключей-кандидатов. Каждый ключ-кандидат представляет собой столбец или набор столбцов, которые являются UNIQUE, взятые вместе, а также NOT NULL. Таким образом, указать значения для всех столбцов любого ключа-кандидата достаточно, чтобы определить, что существует одна строка, которая соответствует критериям, или вообще не содержит строк.

Ключи-кандидаты являются фундаментальной концепцией в реляционной модели данных.

Это обычная практика, если несколько ключей присутствуют в одной таблице, чтобы назначить один из ключей-кандидатов в качестве первичного ключа. Также обычной практикой является заставить любые внешние ключи к таблице ссылаться на первичный ключ, а не на любой другой ключ кандидата.

Я рекомендую эти методы, но в реляционной модели нет ничего, что требует выбора первичного ключа среди ключей-кандидатов.

Ответ 4

Это ответ как для основного вопроса, так и для вопроса @Kalmi о

Какой смысл иметь несколько автогенерирующих столбцов?

Этот код ниже содержит составной первичный ключ. Один из его столбцов автоматически увеличивается. Это будет работать только в MyISAM. InnoDB генерирует ошибку "ERROR 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 |
+--------+----+---------+

Ответ 5

Первичный ключ - очень неудачная нотация из-за коннотации "Первичного" и подсознательной связи, как следствие, с логической моделью. Поэтому я не использую его. Вместо этого я имею в виду суррогатный ключ физической модели и естественный ключ логической модели.

Важно, что логическая модель для каждой сущности имеет по крайней мере один набор "бизнес-атрибутов", которые содержат ключ для объекта. Boyce, Codd, Date et al. Относятся к ним в реляционной модели как к ключам кандидата. Когда мы создаем таблицы для этих объектов, их Ключи-кандидаты становятся естественными ключами в этих таблицах. Только через эти естественные ключи пользователи могут однозначно идентифицировать строки в таблицах; поскольку суррогатные ключи всегда должны быть скрыты от пользователей. Это связано с тем, что суррогатные ключи не имеют никакого коммерческого значения.

Однако физическая модель для наших таблиц во многих случаях будет неэффективной без Суррогатного ключа. Напомним, что незакрытые столбцы для некластеризованного индекса могут быть найдены (в общем) только путем поиска ключа в кластерный индекс (игнорируйте таблицы, выполняемые как кучи на мгновение). Когда наш доступный Natural Key (s) является широким, это (1) расширяет ширину наших некластеризованных листовых узлов, увеличивая требования к хранению и доступ к чтению для поиска и сканирования этого некластеризованного индекса; и (2) уменьшает разветвление от нашего кластерного индекса, увеличивая высоту индекса и размер индекса, снова увеличивая требования к чтению и хранению для наших кластеризованных индексов; и (3) увеличивает требования к кешу для наших кластерных индексов. преследование других индексов и данных из кеша.

Здесь маленький Суррогатный ключ, назначенный РСУБД как "Основной ключ", оказывается полезным. При установке в качестве ключа кластеризации, чтобы использоваться для поиска ключей в кластерном индексе из некластеризованных индексов и поиска внешнего ключа из связанных таблиц, все эти недостатки исчезают. Наши кластерные индексы разворачиваются снова, чтобы уменьшить размер и размер кластеризованных индексов, уменьшить нагрузку на кеш для наших кластерных индексов, уменьшить число просмотров при доступе к данным через любой механизм (будь то сканирование индексов, поиск индекса, поиск некластеризованного ключа или поиск внешнего ключа) и уменьшить требования к хранилищу для кластеризованных и некластеризованных индексов наших таблиц.

Обратите внимание, что эти преимущества возникают только тогда, когда суррогатная клавиша как маленькая, так и клавиша кластеризации. Если в качестве ключа кластеризации используется GUID, ситуация часто будет хуже, чем если бы использовался самый маленький доступный Natural Key. Если таблица организована как куча, тогда 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) декларативно применял это ограничение как "ADD CONSTRAINT pk_PersonID UNIQUE NONCLUSTERED (P_Id, LastName)" и (2) отдельно объявляют маленький суррогатный ключ как "первичный ключ" кластерного индекса. Стоит отметить, что Анита может только пожелать добавить LastName к этому ограничению, чтобы сделать это закрытое поле, которое не нужно в кластерном индексе, потому что все поля покрыты им.

Возможность в SQL Server назначать первичный ключ как некластеризованный является неудачным историческим обстоятельством из-за сочетания значения "предпочтительный естественный или ключ-кандидат" (из логической модели) со значением "ключ поиска в хранилище", от физической модели. Я понимаю, что изначально SYBASE SQL Server всегда использовал 4-байтовый RowID, будь то в кучу или кластерный индекс, как "ключ поиска в хранилище" из физической модели.

Ответ 6

Как отмечают другие, возможно иметь многоколоночные первичные ключи. Однако следует отметить, что если у вас есть некоторые функциональные зависимости, которые не вводятся ключом, вы должны рассмотреть нормализация вашего отношения.

Пример:

Person(id, name, email, street, zip_code, area)

Между id -> name,email, street, zip_code and area может существовать функциональная зависимость, Но часто a zip_code связывается с a area и, следовательно, между zip_code -> area существует внутренняя функциональная зависимость.

Таким образом, можно рассмотреть разбиение его на другую таблицу:

Person(id, name, email, street, zip_code)
Area(zip_code, name)

Так, чтобы он соответствовал третьей нормальной форме .

Ответ 7

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

В некоторых других брендах базы данных вы можете определить более одного столбца автогенерации в таблице.

Ответ 8

Первичный ключ - это ключ, который уникально идентифицирует запись и используется во всех индексах. Вот почему у вас не может быть более одного. Он также обычно является ключом, который используется для присоединения к дочерним таблицам, но это не является обязательным требованием. Реальная цель ПК заключается в том, чтобы убедиться, что что-то позволяет вам однозначно идентифицировать запись, чтобы изменения данных влияли на правильную запись и чтобы индексы могли быть созданы.

Однако вы можете поместить несколько полей в один первичный ключ (составной ПК). Это сделает ваши соединения медленнее (особенно, если они больше полей типа строки), а ваши индексы больше, но это может устранить необходимость делать объединения в некоторых дочерних таблицах, так что, насколько производительность и дизайн, возьмите его по делу случай основы. Когда вы это делаете, каждое само поле не уникально, но их комбинация. Если одно или несколько полей в составном ключе также должны быть уникальными, вам нужен уникальный индекс. Вероятно, что если одно поле уникально, это лучший кандидат для ПК.

Теперь время от времени у вас более одного кандидата на ПК. В этом случае вы выбираете один из них как ПК или используете суррогатный ключ (я лично предпочитаю суррогатные ключи для этого экземпляра). И (это важно!) Вы добавляете уникальные индексы к каждому из ключей-кандидатов, которые не были выбраны в качестве ПК. Если данные должны быть уникальными, для этого нужен уникальный индекс, будь то ПК или нет. Это проблема целостности данных. (Обратите внимание, что это также верно в любое время, когда вы используете суррогатный ключ, люди сталкиваются с проблемами с суррогатными ключами, потому что они забывают создавать уникальные индексы на ключах-кандидатах.)

Иногда случаются случаи, когда вам требуется более одного суррогатного ключа (обычно это ПК, если у вас есть). В этом случае вы не больше PK, больше полей с автогенерированными ключами. Большинство БД этого не допускают, но есть способы обойти это. Сначала рассмотрим, может ли второе поле быть рассчитано на основе первого автогенерированного ключа (например, Field1 * -1) или, возможно, необходимость второго автогенерированного ключа на самом деле означает, что вы должны создать связанную таблицу. Связанные таблицы могут быть взаимно однозначными. Вы должны обеспечить это, добавив PK из родительской таблицы в дочернюю таблицу, а затем добавив в таблицу новое автоматически генерируемое поле, а затем все поля, подходящие для этой таблицы. Затем выберите одну из двух клавиш в качестве PK и поместите уникальный индекс на другое (автогенерируемое поле не обязательно должно быть PK). И не забудьте добавить FK в поле, которое находится в родительской таблице. В общем случае, если у вас нет дополнительных полей для дочерней таблицы, вам нужно изучить, почему вы считаете, что вам нужны два автоматически генерируемых поля.

Ответ 9

Хорошие технические ответы были даны лучше, чем я могу. Я могу только добавить в эту тему:

Если вы хотите что-то, что не разрешено/приемлемо, это хорошая причина сделать шаг назад.

  • Понять суть проблемы, почему это неприемлемо.
  • Подробнее в документах/журнальных статьях/Интернете и т.д.
  • Анализировать/анализировать текущий дизайн и указывать основные недостатки.
  • Рассмотрите и протестируйте каждый шаг во время нового дизайна.
  • Всегда смотрите вперед и пытайтесь создать адаптивное решение.

Надеюсь, это поможет кому-то.

Ответ 10

Наличие двух первичных ключей одновременно невозможно. Но (предполагая, что вы не испортили дело со сложным ключом), может оказаться, что вам может понадобиться сделать один атрибут уникальным.

CREATE t1(
c1 int NOT NULL,
c2 int NOT NULL UNIQUE,
...,
PRIMARY KEY (c1)
);

Однако обратите внимание, что в реляционной базе данных "супер ключ" представляет собой подмножество атрибутов, которые однозначно идентифицируют кортеж или строку в таблице. "Ключ" - это "супер-ключ", который имеет дополнительное свойство, которое удаляет любой атрибут из ключа, делает этот ключ не более "супер-ключ" (или просто "ключ" - это минимальный супер-ключ). Если ключей больше, все они являются ключами-кандидатами. Мы выбираем один из ключей-кандидатов в качестве первичного ключа. Поэтому говорить о нескольких первичных ключах для одного отношения или таблицы является конфликтом.

Ответ 11

Да, его возможно в 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)
);