0

Apache Derby Bài 10: Ràng buộc kiểm tra (CHECK) và giá trị mặc định (DEFAULT)

1. Vai trò của DEFAULT và CHECK

Trong thiết kế cơ sở dữ liệu quan hệ, ngoài việc đảm bảo tính duy nhất và liên kết thực thể (khóa chính, khóa ngoại), chúng ta cần bảo vệ tính hợp lệ của từng trường dữ liệu:

  • Mệnh đề DEFAULT: Tự động điền giá trị chuẩn khi câu lệnh INSERT không truyền dữ liệu cho cột đó. Giúp giảm bớt độ dài câu lệnh SQL và tránh lỗi thiếu dữ liệu.

  • Ràng buộc CHECK: Thiết lập biểu thức điều kiện logic (Boolean expression). Mọi thao tác INSERT hoặc UPDATE làm biểu thức này trả về FALSE đều bị hệ thống chặn lại ngay lập tức.

Cả hai cơ chế này chạy trực tiếp bên trong engine của Derby, giúp giảm thiểu rủi ro dữ liệu rác lọt vào kho lưu trữ ngay cả khi tầng ứng dụng (Java, Web API) bị lỗi kiểm tra dữ liệu đầu vào (validation).

2. Giá trị mặc định (DEFAULT) trong Derby

Mệnh đề DEFAULT được khai báo ngay sau kiểu dữ liệu của cột. Giá trị mặc định có thể là:

  1. Hằng số (số nguyên, chuỗi ký tự, số thực).

  2. Biểu thức hoặc hằng giá trị hệ thống (NULL, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, USER).

SQL

CREATE TABLE tai_khoan (
    id INT NOT NULL,
    ten_dang_nhap VARCHAR(50) NOT NULL,
    vai_tro VARCHAR(20) DEFAULT 'MEMBER',
    diem_tich_luy INT DEFAULT 0,
    kich_hoat SMALLINT DEFAULT 1,
    thoi_gian_tao TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT pk_tai_khoan PRIMARY KEY (id)
);

Cách thức hoạt động khi chèn dữ liệu:

  • Kịch bản 1: Không khai báo cột trong danh sách INSERT

    SQL

    INSERT INTO tai_khoan (id, ten_dang_nhap) VALUES (1, 'dev_hieu');
    -- vai_tro sẽ là 'MEMBER', diem_tich_luy = 0, kich_hoat = 1
    
    
  • Kịch bản 2: Sử dụng từ khóa DEFAULT một cách tường minh

    SQL

    INSERT INTO tai_khoan (id, ten_dang_nhap, vai_tro, diem_tich_luy) 
    VALUES (2, 'admin_root', 'ADMIN', DEFAULT);
    -- diem_tich_luy tự động nhận giá trị 0
    
    

3. Ràng buộc kiểm tra (CHECK) trong Derby

Ràng buộc CHECK yêu cầu một biểu thức logic đánh giá điều kiện. Trong Derby, biểu thức CHECK cần tuân thủ các quy tắc nghiêm ngặt:

  • Phải đánh giá ra kết quả TRUE, FALSE, hoặc UNKNOWN (với giá trị NULL). Thao tác chỉ bị chặn khi kết quả là FALSE.

  • Biểu thức chỉ được tham chiếu đến các cột trong cùng một bảng.

  • Không được chứa: Truy vấn con (Subquery), hàm biến đổi theo thời gian (CURRENT_DATE, CURRENT_TIMESTAMP), hoặc các cột của bảng khác.

1. Khai báo ở cấp độ cột

Thường dùng khi điều kiện chỉ kiểm tra trên chính cột đó:

SQL

tuoi INT CONSTRAINT chk_tuoi CHECK (tuoi >= 18 AND tuoi <= 65)

2. Khai báo ở cấp độ bảng

Bắt buộc sử dụng khi điều kiện kiểm tra có sự phối hợp giữa nhiều cột trong cùng một dòng:

SQL

CONSTRAINT chk_gia_ban CHECK (gia_khuyen_mai <= gia_goc)

4. Các mẫu ràng buộc CHECK phổ biến

Mẫu 1: Kiểm tra khoảng giá trị (Range Check)

Đảm bảo điểm số, phần trăm hoặc số lượng nằm trong giới hạn cho phép:

SQL

diem_so DECIMAL(4, 2) CONSTRAINT chk_diem_hop_le CHECK (diem_so >= 0.0 AND diem_so <= 10.0)

Mẫu 2: Giới hạn danh sách giá trị cho phép (Enum Pattern)

Vì Derby không có kiểu dữ liệu ENUM nguyên bản, ta dùng CHECK (cột IN (...)) để mô phỏng:

SQL

trang_thai VARCHAR(20) CONSTRAINT chk_trang_thai_don_hang 
CHECK (trang_thai IN ('CHO_XU_LY', 'DANG_GIAO', 'HOAN_THANH', 'DA_HUY'))

Mẫu 3: So sánh logic giữa nhiều cột (Cross-column Validation)

Đảm bảo ngày kết thúc luôn lớn hơn hoặc bằng ngày bắt đầu:

SQL

CONSTRAINT chk_thoi_gian_hop_le CHECK (ngay_ket_thuc >= ngay_bat_dau)

5. Thực hành: Xây dựng bảng hoàn chỉnh và kiểm thử

Mở tiện ích ij và chạy khối lệnh tạo bảng quản lý phiếu giảm giá (Voucher):

SQL

CONNECT 'jdbc:derby:firstdb';

CREATE TABLE phieu_giam_gia (
    ma_voucher VARCHAR(20) NOT NULL,
    ten_chuong_trinh VARCHAR(100) NOT NULL,
    loai_giam_gia VARCHAR(15) DEFAULT 'TIEN_MAT',
    gia_tri_giam DECIMAL(10, 2) NOT NULL,
    don_hang_toi_thieu DECIMAL(12, 2) DEFAULT 0.00,
    so_luot_dung INT DEFAULT 1,
    ngay_bat_dau DATE NOT NULL,
    ngay_het_han DATE NOT NULL,
    
    CONSTRAINT pk_phieu_giam_gia PRIMARY KEY (ma_voucher),
    
    -- Kiểm tra loại giảm giá chỉ được phép 1 trong 2 loại
    CONSTRAINT chk_loai_giam_gia 
        CHECK (loai_giam_gia IN ('TIEN_MAT', 'PHAN_TRAM')),
        
    -- Giá trị giảm và đơn hàng tối thiểu phải lớn hơn 0
    CONSTRAINT chk_gia_tri_duong 
        CHECK (gia_tri_giam > 0 AND don_hang_toi_thieu >= 0),
        
    -- Số lượt dùng tối thiểu là 1
    CONSTRAINT chk_so_luot 
        CHECK (so_luot_dung > 0),
        
    -- Ngày hết hạn phải sau hoặc bằng ngày bắt đầu
    CONSTRAINT chk_han_su_dung 
        CHECK (ngay_het_han >= ngay_bat_dau)
);

Thử nghiệm 1: Chèn bản ghi hợp lệ sử dụng giá trị mặc định

SQL

INSERT INTO phieu_giam_gia (
    ma_voucher, ten_chuong_trinh, gia_tri_giam, ngay_bat_dau, ngay_het_han
) VALUES (
    'KM2026', 'Mung nam moi 2026', 50000.00, '2026-10-10', '2026-10-20'
);

Kết quả: Chèn thành công. Cột loai_giam_gia tự động nhận giá trị 'TIEN_MAT', so_luot_dung nhận giá trị 1.

Thử nghiệm 2: Cố tình vi phạm điều kiện logic của CHECK

Thử chèn phiếu có ngay_het_han nằm trước ngay_bat_dau:

SQL

INSERT INTO phieu_giam_gia (
    ma_voucher, ten_chuong_trinh, gia_tri_giam, ngay_bat_dau, ngay_het_han
) VALUES (
    'ERR_VOUCHER', 'Khuyen mai sai ngay', 20000.00, '2026-10-15', '2026-10-01'
);

Derby sẽ chặn câu lệnh và ném mã lỗi vi phạm kiểm tra 23513:

Plaintext

ERROR 23513: The check constraint 'CHK_HAN_SU_DUNG' was violated while performing an INSERT on table 'PHIEU_GIAM_GIA'.

6. Tổng kết

  • Mệnh đề DEFAULT hỗ trợ gán giá trị khởi tạo tĩnh hoặc các hàm thời gian/người dùng hệ thống (CURRENT_TIMESTAMP).

  • Ràng buộc CHECK đóng vai trò chốt chặn cuối cùng bảo vệ tính đúng đắn của dữ liệu, thay thế cho kiểu ENUM bằng cú pháp IN (...).

  • Biểu thức trong CHECK chỉ kiểm tra nội bộ trên cùng một hàng của bảng đó, không cho phép truy vấn lồng hay gọi hàm thời gian động.

Bài tiếp theo sẽ đi vào nhóm thao tác dữ liệu cốt lõi: Apache Derby Bài 11: Thao tác dữ liệu cơ bản: INSERT, UPDATE, DELETE và SELECT.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí