Если вы использовали имя человека в качестве первичного ключа и его имя изменилось, вам необходимо изменить первичный ключ. Это то, что ON UPDATE CASCADE
используется, так как по существу каскадные изменения касаются всех связанных таблиц, которые имеют отношение внешнего ключа к первичному ключу.
Например:
USE tempdb;
GO
CREATE TABLE dbo.People
(
PersonKey VARCHAR(200) NOT NULL
CONSTRAINT PK_People
PRIMARY KEY CLUSTERED
, BirthDate DATE NULL
) ON [PRIMARY];
CREATE TABLE dbo.PeopleAKA
(
PersonAKAKey VARCHAR(200) NOT NULL
CONSTRAINT PK_PeopleAKA
PRIMARY KEY CLUSTERED
, PersonKey VARCHAR(200) NOT NULL
CONSTRAINT FK_PeopleAKA_People
FOREIGN KEY REFERENCES dbo.People(PersonKey)
ON UPDATE CASCADE
) ON [PRIMARY];
INSERT INTO dbo.People(PersonKey, BirthDate)
VALUES ('Joe Black', '1776-01-01');
INSERT INTO dbo.PeopleAKA(PersonAKAKey, PersonKey)
VALUES ('Death', 'Joe Black');
А SELECT
против обеих таблиц:
SELECT *
FROM dbo.People p
INNER JOIN dbo.PeopleAKA pa ON p.PersonKey = pa.PersonKey;
Возвращает:
Если мы обновим PersonKey
столбец и снова запустим SELECT
:
UPDATE dbo.People
SET PersonKey = 'Mr Joe Black'
WHERE PersonKey = 'Joe Black';
SELECT *
FROM dbo.People p
INNER JOIN dbo.PeopleAKA pa ON p.PersonKey = pa.PersonKey;
мы видим:
Рассматривая план вышеприведенного UPDATE
оператора, мы ясно видим, что обе таблицы обновляются одним оператором обновления благодаря внешнему ключу, определенному как ON UPDATE CASCADE
:
нажмите на изображение выше, чтобы увидеть его в большей ясности
Наконец, мы очистим наши временные таблицы:
DROP TABLE dbo.PeopleAKA;
DROP TABLE dbo.People;
Удобнее всего 1 способ сделать это с помощью суррогатных ключей будет:
USE tempdb;
GO
CREATE TABLE dbo.People
(
PersonID INT NOT NULL IDENTITY(1,1)
CONSTRAINT PK_People
PRIMARY KEY CLUSTERED
, PersonName VARCHAR(200) NOT NULL
, BirthDate DATE NULL
) ON [PRIMARY];
CREATE TABLE dbo.PeopleAKA
(
PersonAKAID INT NOT NULL IDENTITY(1,1)
CONSTRAINT PK_PeopleAKA
PRIMARY KEY CLUSTERED
, PersonAKAName VARCHAR(200) NOT NULL
, PersonID INT NOT NULL
CONSTRAINT FK_PeopleAKA_People
FOREIGN KEY REFERENCES dbo.People(PersonID)
ON UPDATE CASCADE
) ON [PRIMARY];
INSERT INTO dbo.People(PersonName, BirthDate)
VALUES ('Joe Black', '1776-01-01');
INSERT INTO dbo.PeopleAKA(PersonID, PersonAKAName)
VALUES (1, 'Death');
SELECT *
FROM dbo.People p
INNER JOIN dbo.PeopleAKA pa ON p.PersonID = pa.PersonID;
UPDATE dbo.People
SET PersonName = 'Mr Joe Black'
WHERE PersonID = 1;
Для полноты, план для оператора update очень прост и показывает одно преимущество для суррогатных ключей, а именно, необходимо обновить только одну строку, в отличие от каждой строки, содержащей ключ в сценарии с естественным ключом:
SELECT *
FROM dbo.People p
INNER JOIN dbo.PeopleAKA pa ON p.PersonID = pa.PersonID;
DROP TABLE dbo.PeopleAKA;
DROP TABLE dbo.People;
Вывод из двух SELECT
утверждений выше:
По сути, результат примерно одинаков. Одним из основных отличий является то, что широкий естественный ключ не повторяется в каждой таблице, где встречается внешний ключ. В моем примере я использую VARCHAR(200)
столбец для хранения имени человека, что требует использования VARCHAR(200)
везде . Если есть много строк и много таблиц, содержащих внешний ключ, это приведет к большой потере памяти. Заметьте, я не говорю о том, что дисковое пространство теряется, так как большинство людей говорит, что дисковое пространство настолько дешево, что оно по существу свободно. Память, однако, дорогая и заслуживает заботы. Использование 4-байтового целого числа для ключа сэкономит большой объем памяти, если учесть среднюю длину имени около 15 символов.
Касательно вопроса о том, как и почему ключи могут изменяться, возникает вопрос о том, почему следует выбирать естественные ключи вместо суррогатных ключей, что является интересным и, возможно, более важным вопросом, особенно в тех случаях, когда производительность является целью проектирования. Смотрите мой вопрос здесь об этом.
1 - http://weblogs.sqlteam.com/mladenp/archive/2009/10/06/Why-I-prefer-surrogate-keys-instead-of-natural-keys-in.aspx