Nếu bạn đang sử dụng tên của một người làm khóa chính và tên của họ đã thay đổi, bạn sẽ cần thay đổi khóa chính. Đây là những gì ON UPDATE CASCADE
được sử dụng vì về cơ bản nó xếp tầng thay đổi xuống tất cả các bảng có liên quan có mối quan hệ khóa ngoài với khóa chính.
Ví dụ:
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');
A SELECT
so với cả hai bảng:
SELECT *
FROM dbo.People p
INNER JOIN dbo.PeopleAKA pa ON p.PersonKey = pa.PersonKey;
Trả về:
Nếu chúng tôi cập nhật PersonKey
cột và chạy lại 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;
chúng tôi thấy:
Nhìn vào kế hoạch cho UPDATE
tuyên bố trên , chúng ta thấy rõ cả hai bảng được cập nhật bởi một tuyên bố cập nhật duy nhất nhờ khóa ngoại được xác định là ON UPDATE CASCADE
:
nhấp vào hình ảnh trên để thấy rõ hơn
Cuối cùng, chúng tôi sẽ dọn sạch các bảng tạm thời của chúng tôi:
DROP TABLE dbo.PeopleAKA;
DROP TABLE dbo.People;
Cách 1 ưu tiên để thực hiện việc này bằng các phím thay thế sẽ là:
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;
Để đầy đủ, kế hoạch cho câu lệnh cập nhật rất đơn giản và cho thấy một lợi thế để thay thế các khóa, cụ thể là chỉ một hàng duy nhất cần được cập nhật trái ngược với mọi hàng có chứa khóa trong kịch bản khóa tự nhiên:
SELECT *
FROM dbo.People p
INNER JOIN dbo.PeopleAKA pa ON p.PersonID = pa.PersonID;
DROP TABLE dbo.PeopleAKA;
DROP TABLE dbo.People;
Đầu ra từ hai SELECT
câu lệnh trên là:
Về cơ bản, kết quả là gần như nhau. Một điểm khác biệt chính là khóa tự nhiên rộng không được lặp lại trong mỗi bảng nơi xảy ra khóa ngoại. Trong ví dụ của tôi, tôi đang sử dụng một VARCHAR(200)
cột để giữ tên của người đó, điều này bắt buộc phải sử dụng VARCHAR(200)
ở mọi nơi . Nếu có rất nhiều hàng và rất nhiều bảng chứa khóa ngoại, điều đó sẽ làm tăng thêm rất nhiều bộ nhớ lãng phí. Lưu ý, tôi không nói về việc dung lượng ổ đĩa bị lãng phí vì hầu hết mọi người nói rằng dung lượng ổ đĩa rẻ đến mức về cơ bản là miễn phí. Bộ nhớ, tuy nhiên, đắt tiền và xứng đáng được trân trọng. Sử dụng số nguyên 4 byte cho khóa sẽ tiết kiệm một lượng lớn bộ nhớ khi bạn xem xét độ dài tên trung bình khoảng 15 ký tự.
Tiếp theo câu hỏi về cách thức và lý do tại sao các phím có thể thay đổi là câu hỏi về lý do tại sao chọn khóa tự nhiên thay vì khóa thay thế, đây là một câu hỏi thú vị và có lẽ quan trọng hơn, đặc biệt là hiệu suất là mục tiêu thiết kế. Xem câu hỏi của tôi ở đây về điều đó.
1 - http://weblogs.sqlteam.com/mladenp/archive/2009/10/06/Why-I-prefer-surrogate-keys-instead-of-natural-keys-in.aspx