คำสั่ง INSERT ... ON DUPLICATE KEY UPDATE ต้องการให้มี Unique Constraint (Primary Key หรือ Unique Index) บนคอลัมน์ที่ตรวจสอบ Duplicate เพื่อทราบว่าระเบียน "ซ้ำ" ตามคีย์ไหน จึงจะ Update แทน Insert
ตัวอย่างการใช้งาน
สร้างตาราง:
mysql> CREATE TABLE DemoTable1459 (Name VARCHAR(20), Score INT);
เพิ่ม Unique Constraint บน Name:
mysql> ALTER TABLE DemoTable1459 ADD CONSTRAINT Name_const UNIQUE (Name);
Insert พร้อม ON DUPLICATE KEY UPDATE:
mysql> INSERT INTO DemoTable1459 VALUES ('Chris', 57) ON DUPLICATE KEY UPDATE Score = Score + 10;
Query OK, 1 row affected (0.12 sec) -- Insert ใหม่
mysql> INSERT INTO DemoTable1459 VALUES ('David', 89) ON DUPLICATE KEY UPDATE Score = Score + 10;
Query OK, 1 row affected (0.11 sec) -- Insert ใหม่
mysql> INSERT INTO DemoTable1459 VALUES ('Chris', 78) ON DUPLICATE KEY UPDATE Score = Score + 10;
Query OK, 2 rows affected (0.33 sec) -- Duplicate! Update Score: 57+10=67
ดูผลลัพธ์:
mysql> SELECT * FROM DemoTable1459; +-------+-------+ | Name | Score | +-------+-------+ | Chris | 67 | | David | 89 | +-------+-------+
ไวยากรณ์ Constraint
ALTER TABLE table_name ADD CONSTRAINT constraint_name UNIQUE (column_name);
- CONSTRAINT name: ชื่อ Constraint (Optional แต่แนะนำให้ตั้ง)
- UNIQUE (col): สร้าง Unique Index
ประเภท Key ที่รองรับ ON DUPLICATE KEY UPDATE
- PRIMARY KEY
- UNIQUE INDEX / UNIQUE CONSTRAINT
- Unique Key ที่สร้างด้วย CREATE UNIQUE INDEX
คำสั่งที่เกี่ยวข้อง
-- ดู Constraints SHOW CREATE TABLE DemoTable1459; SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = 'DemoTable1459'; -- ลบ Constraint ALTER TABLE DemoTable1459 DROP INDEX Name_const; -- MySQL ใช้ DROP INDEX สำหรับ UNIQUE -- สร้าง Unique Index โดยตรง (ไม่ต้อง CONSTRAINT) CREATE UNIQUE INDEX idx_name ON DemoTable1459 (Name);
กรณีการใช้งานจริง (Upsert Pattern)
-- นับ Page Views
INSERT INTO page_views (page_url, view_count, last_viewed)
VALUES ('/home', 1, NOW())
ON DUPLICATE KEY UPDATE view_count = view_count + 1, last_viewed = NOW();
-- Upsert User Profile
INSERT INTO users (email, name, updated_at)
VALUES ('john@example.com', 'John', NOW())
ON DUPLICATE KEY UPDATE name = 'John', updated_at = NOW();
ข้อควรระวัง
- VALUES() ใน UPDATE clause อ้างถึงค่าที่ INSERT เข้าไป (เช่น
VALUES(Score)= 78) - Rows Affected: 1 = Insert ใหม่, 2 = Update มีการเปลี่ยนแปลง, 0 = Duplicate แต่ค่าเหมือนเดิม
- Race Condition: ใน High Concurrency อาจเกิด Deadlock → ใช้ Transaction + Locking หรือ INSERT IGNORE + UPDATE แยก