ПЕРВИЧНЫЕ КЛЮЧИ против УНИКАЛЬНЫХ Ограничений - PullRequest
5 голосов
/ 11 февраля 2012

В статье Александра Кузнецова он представляет следующий фрагмент кода:

CREATE TABLE dbo.Vehicles(
    ID INT NOT NULL, 
    [Type] VARCHAR(5) NOT NULL,
    CONSTRAINT Vehicles_PK PRIMARY KEY(ID),
    CONSTRAINT Vehicles_UNQ_ID_Type UNIQUE(ID, [Type]),
    CONSTRAINT Vehicles_CHK_ValidTypes CHECK([Type] IN ('Car', 'Truck'))
);

Этот фрагмент вызывает у меня несколько вопросов.

  1. Почему необходимо включать ID и Type в ограничение уникальности?Если просто ID является уникальным, то комбинация двух столбцов также всегда будет уникальной.

  2. Кроме того, я знаю, как установить первичный ключ и указать, является ли он уникальным вSSMS.Но как мне указать первичный ключ для одного столбца и создать уникальное ограничение для комбинации столбцов?Создает ли это два индекса?

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

Столбцы в таблице 'MyTable' не соответствуют существующему первичному ключу или уникальному ограничению.


РЕДАКТИРОВАТЬ

Мне удалось добиться этого, просто создав составной первичный ключ в MyTable.Фактическое определение таблицы показано ниже.Опять же, это работает.Но это не то же самое, что приведенный выше код.И я не уверен, что будет лучше, если я сделаю это по-другому.

CREATE TABLE [dbo].[MessageThread](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [MessageThreadType] [int] NOT NULL,
    CONSTRAINT [PK_MessageThread_1] PRIMARY KEY CLUSTERED 
    (
        [Id] ASC,
        [MessageThreadType] ASC
    ) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[MessageThread]  WITH CHECK ADD  CONSTRAINT [CK_MessageThread_ValidType] CHECK  (([MessageThreadType]=(2) OR [MessageThreadType]=(1)))
GO

ALTER TABLE [dbo].[MessageThread] CHECK CONSTRAINT [CK_MessageThread_ValidType]
GO

Ответы [ 5 ]

7 голосов
/ 11 февраля 2012

1: я не уверен в конкретной цели данной схемы. Но обратите внимание, что уникальное ограничение может быть применено по нескольким причинам, чаще всего: (a) до обеспечения уникальности и (b) для предоставления оптимизатору дополнительной информации для базовых решений.

2: уникальное ограничение не создает два индекса. Он создает один индекс с одним из столбцов в качестве ведущего ключевого столбца. Это обеспечивает уникальность обоих. Таким образом, уникальное ограничение для a, b может иметь:

a    b    
---- ----
1    1
1    2
2    1
2    2

Обратите внимание, что ни один из столбцов не обеспечивает уникальность в отдельности. Я не большой поклонник использования конструктора таблиц в SSMS (он содержит множество ошибок и не поддерживает все функции), но вот как это сделать:

a) щелкните правой кнопкой мыши сетку и выберите Indexes/Keys...

б) выбрать несколько столбцов с помощью кнопки [...] в сетке Columns

в) изменить Type на Unique Key

г) изменить Name при желании

enter image description here

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

enter image description here

7 голосов
/ 11 февраля 2012

В моем понимании причина уникального ограничения на ID,[Type] заключается в том, что в таблицах подробностей указывается ID,[Type] как внешний ключ.Обычно родительская таблица должна иметь уникальное ограничение на столбцы, используемые для внешнего ключа.Например, таблица в вопросе может иметь 2 таблицы подробностей:

CREATE TABLE dbo.CARS( 
....
vehicle_id INT NOT NULL,
[Type] VARCHAR(5) NOT NULL,
CONSTRAINT CAR_CHK_TYPE CHECK [Type]='Car',
CONSTRAINT CAR_FK_VEHICLE FOREIGN KEY (vehicle_id,[Type]) REFERENCES Vehincle(id,[Type]));

CREATE TABLE dbo.TRUCKS( 
....
vehicle_id INT NOT NULL,
[Type] VARCHAR(5) NOT NULL,
CONSTRAINT CAR_CHK_TYPE CHECK [Type]='Truck',
CONSTRAINT CAR_FK_VEHICLE FOREIGN KEY (vehicle_id,[Type]) REFERENCES Vehincle(id,[Type]));

Таким образом, Cars будет иметь сведения только о типе Car, тогда как TRUCKS только о Truck.

Такой дизайн используется, чтобы избежать полиморфных отношений, например

CREATE TABLE dbo.VEHICLE (
...,
ref_id INT NOT NULL,
-- PK of 'master' table
ref_name VARCHAR(20) NOT NULL, 
-- here we put 'truck' or 'car', so we virtually have 2 parents; 
-- in this case we cannot use FK constraint, the only thing that may 
-- somehow enforce the logical constraint is writing a trigger

Обновление

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

4 голосов
/ 11 февраля 2012

Вот, пожалуйста,

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

  2. Тем не менее, легковые и грузовые автомобили имеют некоторые атрибуты, такие как VIN (идентификационный номер транспортного средства).Более того, VIN уникален.Вот почему мне нужен стол Транспорт.Транспортное средство не может быть как легковым, так и грузовым, поэтому я должен убедиться, что невозможно ввести оба (VIN = 123456789, Type = Car) и (VIN = 123456789, Type = Truck).Вот почему у меня есть PK только на VIN.

  3. Я должен убедиться, что транспортное средство не может иметь соответствующие строки в таблицах «Автомобили» и «Грузовые автомобили».Вот почему у меня есть столбец «Тип» в «Автомобили и грузовики», и именно поэтому я хочу (VIN, «Тип») в дочерних таблицах «Автомобили и грузовики» ссылаться на родительскую таблицу «Транспортные средства».Единственная причина, по которой мне нужно дополнительное уникальное ограничение для (VIN, Тип), заключается в следующем: на него ссылаются ограничения FK из дочерних таблиц.

Кстати, вы можете оставить комментарий кблог - в этом случае sqlblog отправит мне сообщение.Это совпадение, что я заметил твой вопрос здесь;Я должен был кататься на лыжах, только снега нет.

4 голосов
/ 11 февраля 2012

Я подозреваю, что причина наличия обоих столбцов в ограничении UNIQUE связана с сообщением об ошибке, которое вы упомянули. SQL Server (как и другие СУБД SQL) имеет ограничение, заключающееся в том, что ограничение FOREIGN KEY может ссылаться только на набор столбцов, определенный ограничением уникальности. Поэтому, если ограничение FOREIGN KEY ссылается на два столбца, эти два столбца должны иметь ограничение уникальности - даже если другие ограничения уже гарантируют уникальность. Это бессмысленное ограничение, но оно является частью стандартного SQL.

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

http://consultingblogs.emc.com/davidportas/archive/2007/01/08/Distributed-Keys-and-Disjoint-Subtypes.aspx

4 голосов
/ 11 февраля 2012
  1. Хороший вопрос. Теоретически ты прав; нет никаких причин, запись всегда может быть однозначно идентифицирована ее PK, и уникальное ограничение всегда будет выполняться, пока это верно. Тем не менее, если ID и Тип имеют некоторую взаимосвязь за пределами уровня данных (может быть, эта таблица является моделью данных для Enum?), Маловероятно, что будут два разных идентификатора с одним и тем же типом, поскольку уникальность типа применяется в другом месте. Ограничение также устанавливает индекс, который включает в себя как ID, так и тип, что делает таблицу относительно эффективной для запроса этой комбинации столбцов.

  2. Вы устанавливаете уникальное ограничение, используя опцию «Управление индексами и ключами». Да, это создаст индекс и ограничение уникальности для первичного ключа, а также индекс и ограничение уникальности для комбинации PK и Type.

...