Một unique constraint được sử dụng để đảm bảo những giá trị ở trong một cột (hoặc một bộ nhiều cột) trong một bảng là duy nhất
Cách tạo unique constraint
Chúng ta có thể tạo unique constraint cùng với lúc tạo mới một bảng hoặc chúng ta cũng có thể thêm unique constraint vào bảng đã tồn tại, dưới đây mình sẽ thực hiện tạo unique constraint trong khi tạo mới một bảng
/*Tất cả ví dụ của bài viết sẽ được thực hiện trên AZSqlserver database nên trước khi đi vào phần demo bên dưới chúng ta sẽ tạo database này */
USE master
GO
/*Xóa AZSqlserver database nếu database này đã tồn tại trước đó*/
IF DB_ID('AZSqlserver') IS NOT NULL
BEGIN
ALTER DATABASE AZSqlserver SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE AZSqlserver ;
END
/*Tạo AZSqlserver database*/
CREATE DATABASE AZSqlserver
GO
/*Chúng ta bắt đầu tạo Default Constraints trên cột CreatedDate của bảng Customer*/
USE AZSqlserver
CREATE TABLE dbo.Customer
(
CustomerId INT UNIQUE
,CustomerName VARCHAR(50)
)
GO
Trong phần mềm SQL Server Management Studio bạn ấn vào View → Object Explorer → Databases → AZSqlserver → Tables → dbo.Customer → Keys để xem thông tin default constraint vừa mới được tạo ra
Hình 1
Một điểm đặc biệt là unique constraint được hiển thị trong thư mục Keys, làm cho một số bạn nhầm lẫn giữa unique constraint với primary key, vấn đề nhầm lẫn này mình sẽ trình bày ở phần sau của bài viết, giờ chúng ta cùng phân tích chi tiết tên của unique constraint được sql server tạo tự động
tên của unique constraint trên là UQ__Customer__A4AE64D98270ABAB, trong đó UQ là viết tắt của unique constraint, Customer là tên bảng chứa unique constraint này, A4AE64D98270ABAB là chuỗi ký tự mà sql server tạo tự động để phân biệt tên giữa các unique constraint
để xem thông tin chi tiết của constraint này ta chọn chuột phải → Scripts constraint as → CREATE To → New Query Editor Window
Hình 2
Kết quả :
Hình 3
Kết quả cho ta biết một unique constraint được đặt trên cột CustomerId của bảng dbo.Customer, một điều đặc biệt xuất hiện ở đây là chữ NONCLUSTERED trong câu lệnh ADD UNIQUE NONCLUSTERED, khi ta thêm unique constraint thì một nonclustered index được thêm vào cùng với lúc constraint này được tạo, mục đích của nó là phục vụ quá trình kiểm tra giá trị trùng lặp của constraint
để xem chi tiết nonclustered index này, ta nhấn vào View → Object Explorer → Databases → AZSqlserver → Tables → dbo.Customer → Indexes
Hình 4
Nhấn chuột phải vào nonclustered index, sau đó chọn properties để thấy thông tin của index
Hình 5 – Xem thông tin chi tiết của nonclustered index được tạo ra cùng với unique constraint
Kết quả :
Hình 6 – Thông tin chi tiết của nonclustered index được tạo ra
từ kết quả ta thấy một nonclustered index đã được tạo ra, có tên hiển thị ở phần index name giống như tên của unique constraint hiển thị ở hình 1 là UQ__Customer__A4AE64D98270ABAB, phần index type và checkbox unique được chọn cho ta biết đây là unique nonclustered index, phần index key columns hiển thị cột CustomerId, cho ta biết unique nonclustered index UQ__Customer__A4AE64D98270ABAB có CustomerId là một key columns của nó
Đặt tên cho một unique constraint
Với các đặt tên tự động của sql server như trên, rất khó để chúng ta có thể sử dụng trong các trường hợp như chỉnh sửa nếu cần, để giải quyết vấn đề này ta có thể dùng câu lệnh sau đây để đặt tên unique constraint như ta mong muốn :
USE AZSqlserver
GO
/*Xóa bảng Customer*/
DROP TABLE IF EXISTS dbo.Customer
GO
/*tạo unique constraint với một tên đặt trước*/
CREATE TABLE dbo.Customer
(
CustomerId INT
,CustomerName VARCHAR(50)
,CONSTRAINT unq_CustomerId UNIQUE(CustomerId)
)
GO
Kết quả :
Hình 7 – Unique constraint có tên unq_CustomerId được tạo ra
Thêm unique constraint vào một bảng đã tồn tại trước đó
bảng dbo.Customer ở ví dụ trên hiện tại đang có constraint unq_CustomerId, giờ ta muốn thêm một unique constraint nữa trên cột CustomerName tên là unq_CustomerName ta dùng câu lệnh sau đây :
ALTER TABLE dbo.Customer
ADD CONSTRAINT unq_CustomerName UNIQUE(CustomerName)
Kết quả :
Hình 8 – Thêm unique constraint unq_CustomerName vào bảng dbo.Customer
trong trường hợp muốn tạo unique constraint trên một bộ gồm nhiều cột ta thực hiện như câu lệnh sau đây:
ALTER TABLE dbo.Customer
ADD CONSTRAINT unq_CustomerName_CustomerId UNIQUE(CustomerName, CustomerId)
Kết quả :
Hình 9 – Tạo unique constraint trên nhiều cột
Khi một unique constraint được tạo ra một unique index cũng được tạo ra , mở rộng thư mục indexes ta sẽ thấy điều này
Hình 10 – ba nonclustered indexes được tạo ra khi tạo ba unique constraints
Ở đây có 3 unique index được tạo ra cùng với 3 unique constraint tương ứng
Cả unique constraint và unique index đều có thể dùng cho mục đích đảm bảo dữ liệu của một cột hoặc một bộ gồm nhiều cột không được trùng lặp trong một bảng, tuy nhiên unique constraint và unique index không giống nhau, mình sẽ trình bày sự khác biệt này trong bài viết Sự khác biệt giữa unique index và unique constraint trong sql server
Ví dụ cho cách hoạt động của unique constraint
giờ chúng ta cùng kiểm tra cách thức hoạt động của unique constraint, trước khi làm điều này ta hãy tạo lại bảng dbo.Customer với unique constraint được đặt trên cột CustomerId
USE AZSqlserver
GO
/*Xóa bảng Customer*/
DROP TABLE IF EXISTS dbo.Customer
GO
/*tạo unique constraint với một tên đặt trước*/
CREATE TABLE dbo.Customer
(
CustomerId INT
,CustomerName VARCHAR(50)
,CONSTRAINT unq_CustomerId UNIQUE(CustomerId)
)
GO
Tiếp theo ta insert một dòng vào bảng dbo.Customer
INSERT INTO dbo.Customer
VALUES (1, 'Customer 1')
GO
Hình 11
Câu lệnh đã insert thành công
Tiếp theo ta sẽ insert thêm 1 dòng nữa, có CustomerId = 1, giống với giá trị ở dòng đầu đã insert
INSERT INTO dbo.Customer
VALUES (1, 'Customer 2')
GO
Hình 12 – Lỗi khi insert giá trị trùng lặp vào cột thuộc unique constraint
lúc này một lỗi đã xuất hiện :
Msg 2627, Level 14, State 1, Line 17
Violation of UNIQUE KEY constraint ‘unq_CustomerId’.
Cannot insert duplicate key in object ‘dbo.Customer’. The duplicate key value is (1).
Lỗi nào báo cho ta biết đã vi phạm unique constraint có tên là unq_CustomerId, lý do chi tiết cho sự vi phạm này là ta đã insert một dòng vào bảng dbo.Customer và dòng này gây trùng lặp, cụ thể giá trị gây trùng lặp là 1 (The duplicate key value is (1)) trên cột customerId
Sự khác nhau giữa unique constraint và primary key constraint
unique constraint và primary key constraint đều thực hiện việc tránh trùng lặp dữ liệu trên một số cột mà ta định nghĩa khi tạo unique constraint hoặc primary key constraint, vậy câu hỏi đặt ra là khi nào ta nên lựa chọn dùng unique constraint hay primary key constraint ?
để có thể lựa chọn đúng, ta cần đi vào 2 điểm khác biệt giữa unique constraint và primary key constraint:
Khác biệt #1 : một unique constraint có thể chứa một giá trị NULL
Một primary key constraint không thể chứa bất kỳ giá trị NULL nào, Nếu bạn insert một giá trị NULL vào một trong những cột thuộc primary key thì bạn sẽ nhận về một lỗi, trong khi đó đối với unique constraint vẫn cho phép bạn làm điều đó
Ví dụ : Ta thực hiện insert giá trị NULL vào một cột có unique constraint đặt trên nó xem điều gì sẽ xảy ra
/*Insert giá trị NULL vào cột trong unique constraint*/
USE AZSqlserver
GO
/*Xóa bảng Customer*/
DROP TABLE IF EXISTS dbo.Customer
GO
/*tạo unique constraint với một tên đặt trước*/
CREATE TABLE dbo.Customer
(
CustomerId INT
,CustomerName VARCHAR(50)
,CONSTRAINT unq_CustomerId UNIQUE(CustomerId)
)
GO
/* insert giá trị NULL vào cột CustomerId thuộc unique constraint unq_CustomerId */
INSERT INTO dbo.Customer (CustomerId, CustomerName)
VALUES (NULL, 'Customer 1')
Kết quả :
Hình 13 – insert thành công giá trị NULL vào cột customerId
Giờ ta cùng thử insert giá trị NULL vào primary key constraint
USE AZSqlserver
GO
/*Xóa bảng Customer*/
DROP TABLE IF EXISTS dbo.Customer
GO
/*tạo bảng với primary key được đặt trên cột CustomerId*/
CREATE TABLE dbo.Customer
(
CustomerId INT PRIMARY KEY
,CustomerName VARCHAR(50)
)
GO
/* Chạy câu lệnh Insert giá trị NULL vào cột CustomerId*/
INSERT INTO dbo.Customer (CustomerId, CustomerName)
VALUES (NULL, 'Customer 1')
Kết quả :
Hình 14 – Lỗi khi insert giá trị NULL và một cột CustomerId thuộc primary key
lỗi xuất hiện với nội dung :
Msg 515, Level 16, State 2, Line 17
Cannot insert the value NULL into column ‘CustomerId’,
table ‘AZSqlserver.dbo.Customer’; column does not allow nulls. INSERT fails.
lỗi này cho ta biết không thể insert giá trị NULL vào cột Customerid vì cột này không cho phép giá trị NULL
Khác biệt #2 : Bạn có thể tạo nhiều unique constraint trên một bảng
Bạn chỉ có thể tạo một primary key constraint trên một bảng, nhưng bạn có thể tạo nhiều unique constraint trên bảng đó
Gỡ bỏ một unique constraint :
Bạn chạy câu lệnh sau đây để gỡ bỏ unique constraint unq_CustomerId khỏi bảng dbo.Customer
ALTER TABLE dbo.Customer
DROP CONSTRAINT unq_CustomerId