Câu lệnh INSERT ... ON DUPLICATE KEY UPDATE (upsert) cho phép chèn hàng mới, hoặc cập nhật hàng đã tồn tại nếu vi phạm khóa chính/duy nhất.
Cú pháp chuẩn
INSERT INTO ten_bang (cot_1, cot_2, ...)
VALUES (gt_1, gt_2, ...)
ON DUPLICATE KEY UPDATE
cot_1 = gia_tri_moi_1,
cot_2 = gia_tri_moi_2, ...;
- Kích hoạt khi INSERT gây trùng **PRIMARY KEY** hoặc **UNIQUE KEY**.
- Phần UPDATE có thể dùng giá trị mới, giá trị cũ (
VALUES(cot)), hoặc biểu thức.
Ví dụ minh họa
Bảng nhân viên với UNIQUE KEY trên EmployeeName:
mysql> CREATE TABLE DemoTable1539 (
-> EmployeeName VARCHAR(20),
-> EmployeeSalary INT,
-> UNIQUE KEY(EmployeeName)
-> );
Lần 1: Insert 'Chris' (mới) → INSERT:
mysql> INSERT INTO DemoTable1539 VALUES ('Chris',4500)
-> ON DUPLICATE KEY UPDATE EmployeeName='Robert', EmployeeSalary=8500;
Query OK, 1 row affected
Lần 2: Insert 'David' (mới) → INSERT:
mysql> INSERT INTO DemoTable1539 VALUES ('David',5500)
-> ON DUPLICATE KEY UPDATE EmployeeName='Robert', EmployeeSalary=8500;
Query OK, 1 row affected
Lần 3: Insert lại 'Chris' (trùng UNIQUE) → UPDATE:
mysql> INSERT INTO DemoTable1539 VALUES ('Chris',4500)
-> ON DUPLICATE KEY UPDATE EmployeeName='Robert', EmployeeSalary=8500;
Query OK, 2 rows affected
Kết quả cuối (Chris đã thành Robert, lương 8500):
+--------------+----------------+ | EmployeeName | EmployeeSalary | +--------------+----------------+ | Robert | 8500 | | David | 5500 | +--------------+----------------+
Giải thích
- Lần 3: MySQL tìm thấy 'Chris' (trùng UNIQUE) → chạy UPDATE: đổi tên thành 'Robert', lương 8500.
- Thông báo
2 rows affected= 1 row matched + 1 row updated. - Bảng chỉ còn 2 hàng (Chris đã đổi thành Robert).
Mẹo hay dùng
- Giữ nguyên giá trị cũ:
cot = VALUES(cot)(giá trị từ câu INSERT). - Cộng dồn:
cot = cot + VALUES(cot). - Chỉ cập nhật một số cột: liệt kê những cột cần update.
⚠️ Lưu ý
- Cần có PRIMARY KEY hoặc UNIQUE KEY mới kích hoạt ON DUPLICATE KEY.
- Không hoạt động với FOREIGN KEY violation.
- Trong transaction, lock hành vi phức tạp – test kỹ trước khi dùng production.