CodeGym /Các khóa học /SQL SELF /Làm việc với ràng buộc CHECK để kiểm tra dữ...

Làm việc với ràng buộc CHECK để kiểm tra dữ liệu

SQL SELF
Mức độ , Bài học
Có sẵn

Ràng buộc CHECK — kiểu như một "bảo vệ" ở cửa bảng của bạn vậy. Nó đảm bảo rằng dữ liệu bạn thêm vào bảng phải thỏa mãn một số điều kiện nhất định. Nếu bạn cố nhét vào bảng dữ liệu không hợp lệ, database sẽ từ chối nhận luôn.

Hãy tưởng tượng bạn muốn mở một cửa hàng ở Đức. Nhưng theo luật thì chủ nhật là ngày nghỉ, không được bán hàng hôm đó. Ràng buộc này giống như CHECK trong database. Bạn thử nhập lịch mở cửa: mở 7 ngày/tuần, hệ thống sẽ trả lời ngay: "Nein, nein, chủ nhật là vi phạm. Lịch này không qua kiểm tra đâu!"

Database cũng vậy: nếu bạn nhập giá trị vi phạm quy tắc CHECK, hệ thống sẽ chặn lại, không cho "lỗi logic" lọt vào dữ liệu.

Tại sao cần CHECK?

  1. Giữ chất lượng dữ liệu: CHECK ngăn không cho dữ liệu sai hoặc không hợp lý lọt vào bảng.
  2. Giảm nguy cơ lỗi: thay vì phải tự kiểm tra dữ liệu trước khi insert, bạn có thể giao việc này cho database.
  3. Tự động hóa logic: quy tắc kiểm tra có thể nhúng thẳng vào cấu trúc database, không cần xử lý ở code ứng dụng.

CHECK hoạt động thế nào?

Ràng buộc CHECK được đặt khi tạo bảng hoặc thêm sau bằng lệnh ALTER TABLE. Đây là cú pháp cơ bản:

CREATE TABLE bảng (
    cột kiểu_dữ_liệu CHECK (điều_kiện)
);

điều_kiện — là biểu thức logic phải đúng với mọi giá trị trong cột đó. Nếu điều kiện sai, database sẽ báo lỗi.

Ví dụ 1: Kiểm tra giá trị trong khoảng

Giả sử ta tạo bảng students, tuổi sinh viên (age) phải từ 16 đến 100:

CREATE TABLE students (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    age INTEGER CHECK (age >= 16 AND age <= 100)
);

Bây giờ, nếu bạn thử insert sinh viên tuổi 12, database sẽ "bắt tận tay":

INSERT INTO students (name, age)
VALUES ('Maria Chi', 12);

Lỗi:

ERROR:  new row for relation "students" violates check constraint "students_age_check"
DETAIL:  Failing row contains (1, Maria Chi, 12).

Đấy, database ở đây nghiêm lắm. Chưa đủ 16 tuổi thì khỏi vào nhé.

Ví dụ 2: Kiểm tra định dạng dữ liệu

Giả sử có bảng emails lưu danh sách email. Ta muốn chắc chắn địa chỉ phải có ký tự @ (cách kiểm tra đơn giản thôi):

CREATE TABLE emails (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) CHECK (email LIKE '%@%')
);

Thử thêm một địa chỉ sai định dạng, không có @ xem sao:

INSERT INTO emails (email)
VALUES ('notanemail.com');

Lỗi:

ERROR:  new row for relation "emails" violates check constraint "emails_email_check"
DETAIL:  Failing row contains (1, notanemail.com).

Muốn tránh lỗi thì mọi email phải có ký tự @:

INSERT INTO emails (email) 
VALUES ('example@student.com');

Query này sẽ chạy thành công.

Ví dụ 3: Kiểm tra điều kiện nhiều cột

Ràng buộc CHECK không chỉ kiểm tra một cột, mà còn có thể kiểm tra biểu thức logic liên quan nhiều cột. Ví dụ với bảng employees, lương (salary) phải lớn hơn thưởng (bonus):

CREATE TABLE employees (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    salary NUMERIC CHECK (salary > 0),
    bonus NUMERIC CHECK (bonus >= 0),
    CHECK (salary > bonus)
);

Bây giờ, nếu ai đó cố thêm nhân viên có thưởng lớn hơn lương, database sẽ không cho phép:

INSERT INTO employees (name, salary, bonus)
VALUES ('Otto Lin', 3000, 4000);

Lỗi:

ERROR:  new row for relation "employees" violates check constraint "employees_salary_bonus_check"
DETAIL:  Failing row contains (1, Otto Lin, 3000, 4000).

Ứng dụng thực tế

Ràng buộc CHECK rất hữu ích khi business logic của bạn gắn chặt với giới hạn dữ liệu. Ví dụ:

  1. Shop online: cấm thêm sản phẩm giá âm.
  2. Nền tảng giáo dục: kiểm tra tuổi học viên khi đăng ký khóa học.
  3. Hệ thống y tế: đảm bảo nhiệt độ cơ thể bệnh nhân nằm trong giới hạn cho phép.

Những kiểm tra này không chỉ là lớp bảo mật phụ, mà còn tiết kiệm thời gian và công sức cho dev lẫn user.

Lưu ý và lỗi thường gặp

Khi dùng CHECK, nhớ mấy điểm sau:

  • Biểu thức logic trong CHECK phải đúng với mọi dòng trong bảng. Nếu có dòng nào vi phạm, trước khi thêm ràng buộc phải sửa lại dòng đó.

  • Kiểm tra sẽ không thực hiện nếu giá trị insert là NULL. Nói cách khác, CHECK (age >= 18) sẽ không báo lỗi với age = NULL. Vì bất kỳ biểu thức nào có NULL đều thành "không xác định". Nếu muốn cấm NULL, hãy thêm NOT NULL.

  • Điều kiện phức tạp trong CHECK có thể làm chậm insert/update, nhất là với bảng lớn.

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION