Giới thiệu
Trong quá trình làm việc với cơ sở dữ liệu MySQL, việc chèn dữ liệu là một thao tác cơ bản và thường xuyên. Tuy nhiên, đôi khi chúng ta cần xử lý các tình huống mà dữ liệu mới có thể xung đột với các ràng buộc khóa duy nhất (unique key) hoặc khóa chính (primary key) đã tồn tại. Khi đó, MySQL sẽ mặc định báo lỗi và không cho phép chèn bản ghi trùng lặp.
Bài viết này sẽ trình bày ba phương pháp phổ biến để quản lý và giải quyết các xung đột khóa duy nhất trong MySQL, giúp bạn linh hoạt hơn trong việc kiểm soát hành vi của cơ sở dữ liệu khi chèn dữ liệu.
1. Sử dụng INSERT IGNORE để bỏ qua các bản ghi trùng lặp
Khi bạn cần chèn một lượng lớn dữ liệu và không muốn quá trình chèn bị gián đoạn bởi các bản ghi đã tồn tại, từ khóa IGNORE là một lựa chọn hữu ích. Với INSERT IGNORE, MySQL sẽ bỏ qua bất kỳ hàng nào gây ra lỗi khóa duy nhất và tiếp tục thực hiện chèn các bản ghi hợp lệ còn lại.
Cú pháp và ví dụ:
INSERT IGNORE INTO SanPham (ma_san_pham, ten_san_pham, gia_niem_yet)
VALUES
('SP001', 'Điện thoại XYZ', 15000000),
('SP002', 'Máy tính bảng ABC', 9000000),
('SP001', 'Đồng hồ thông minh', 3000000); -- ma_san_pham 'SP001' bị trùng
Trong ví dụ trên, nếu cột ma_san_pham có ràng buộc khóa duy nhất và 'SP001' đã tồn tại, bản ghi thứ ba ('SP001', 'Đồng hồ thông minh', 3000000) sẽ bị bỏ qua. Các bản ghi có ma_san_pham là 'SP001' và 'SP002' sẽ được chèn thành công (nếu chúng chưa tồn tại trong bảng).
2. Sử dụng REPLACE INTO để thay thế bản ghi cũ
Khi yêu cầu của bạn là thay thế dữ liệu cũ bằng dữ liệu mới trong trường hợp có xung đột khóa duy nhất, câu lệnh REPLACE INTO là giải pháp phù hợp. Về cơ bản, REPLACE INTO hoạt động bằng cách: nếu một bản ghi có khóa duy nhất (hoặc khóa chính) trùng khớp đã tồn tại, nó sẽ xóa bản ghi đó trước, sau đó chèn bản ghi mới vào.
Cú pháp và ví dụ:
REPLACE INTO NguoiDung (id_nguoi_dung, ten_dang_nhap, email, ngay_tao)
VALUES
(1, 'nguyen.van.a', 'a@example.com', '2023-01-10'),
(2, 'tran.thi.b', 'b@example.com', '2023-02-15'),
(1, 'nguyen.van.an', 'an@example.com', '2023-03-20'); -- id_nguoi_dung 1 bị trùng, sẽ thay thế
Nếu id_nguoi_dung là khóa chính, khi bản ghi thứ ba với id_nguoi_dung là 1 được thực thi, bản ghi gốc của 'nguyen.van.a' sẽ bị xóa và sau đó bản ghi của 'nguyen.van.an' sẽ được chèn vào. Kết quả là bản ghi 'nguyen.van.a' không còn tồn tại, thay vào đó là 'nguyen.van.an' với dữ liệu mới. Lệnh này sẽ ảnh hưởng đến 2 hàng (1 xóa, 1 chèn) cho mỗi bản ghi bị trùng.
3. Sử dụng ON DUPLICATE KEY UPDATE để cập nhật có chọn lọc
Đây là phương pháp linh hoạt nhất, cho phép bạn chỉ định cụ thể các cột cần được cập nhật khi có xung đột khóa duy nhất. Thay vì xóa và chèn lại toàn bộ như REPLACE INTO, ON DUPLICATE KEY UPDATE chỉ thực hiện thao tác cập nhật trên bản ghi đã tồn tại.
Cú pháp và ví dụ:
INSERT INTO ThongTinDonHang (ma_dh, ma_khach, ngay_dat_hang, tong_gia_tri, trang_thai)
VALUES
('DH001', 'KH005', '2023-04-01', 1200000, 'Mới')
ON DUPLICATE KEY UPDATE
tong_gia_tri = tong_gia_tri + VALUES(tong_gia_tri), -- Cộng thêm giá trị mới
trang_thai = VALUES(trang_thai), -- Cập nhật trạng thái mới
ngay_cap_nhat = NOW(); -- Cập nhật thời gian hiện tại
Trong ví dụ này, nếu cột ma_dh là khóa duy nhất và 'DH001' đã tồn tại, thay vì báo lỗi, lệnh sẽ cập nhật các cột tong_gia_tri, trang_thai và ngay_cap_nhat của đơn hàng hiện có. Hàm VALUES(cot) được sử dụng để tham chiếu đến giá trị của cột đó trong phần VALUES của câu lệnh INSERT. Điều này cho phép bạn thực hiện các phép tính hoặc gán giá trị mới dựa trên dữ liệu đầu vào.