MySQL -- INSERT ON DUPLICATE KEY UPDATE 使用
阿新 • • 發佈:2019-01-06
前言:
MySQL 中 INSERT ON DUPLICATE KEY UPDATE 這個方法可能不是很常用,但卻很好用,它主要功能是:當插入的資料中的主鍵 與 資料庫中現有的資料主鍵 重複的情況下就不會執行插入操作,而是可以對現有的資料進行更新操作,不存在相同主鍵則執行插入操作。
下面來說說,我為什麼會需要這樣的操作:
假設有表 A,B,C,他們的主鍵分別是 a-pk,b-pk,c-pk
a-pk | b-pk | c-pk | other |
md5(bbcc) | bb | cc | 66 |
md5(2233) | 22 | 33 | 55 |
- 其中A表是報表資料表,它是由 b-pk,c-pk 來確定唯一一條資料,最開始的想法是,通過建立(b-pk,c-pk)的聯合唯一約束 來確保資料行的唯一性,若插入失敗,說明已經存在相同的 b-pk,c-pk 組合,則對 other 欄位進行更新操作。是否可以進行優化一下?不建立聯合唯一約束可以不?
- 因為 b-pk,c-pk,他們本身作為主鍵具有唯一性,由此他們的組合也應當具有唯一性,通過簡單的 b-pk+c-pk 字串拼接可得出一個唯一的字串,可作為 A 表的主鍵 a-pk 的值,這樣可以確保唯一性,也可以免掉 MySQL 獲取自增主鍵所帶來的消耗。
- 同時為了使A表主鍵長度在一定範圍內,所以我們再對 b-pk+c-pk 拼接的字串結果進行 32位 MD5 後作為 A 表的主鍵,MD5 是十六進位制,所以32位的 MD5 個數有 16的32次方個,這個數非常大,40億的4次方個數,除非你的表資料超過了 40億的4次方行,不然不可能會重複的。
- 主鍵是通過 md5(b-pk+c-pk) 外部生成的,所以可以直接利用主鍵唯一性約束來確保資料行唯一性,這樣就不需要建立(b-pk,c-pk)聯合唯一約束。到這裡夠好了嗎?這樣還是需要先插入,失敗則更新,需要兩條SQL,有沒有可以更好的?
- 當然還可以更好,我想了想我這種操作正好適用 插入主鍵重複時做更新操作,於是就用了文章開頭所說的方法 INSERT ON DUPLICATE KEY UPDATE
使用:
1.單條資料插入(以表A為例)
固定更新引數值:
INSERT INTO A (a-pk,b-pk,c-pk,other) VALUES (md5(bbcc),bb,cc,666) ON DUPLICATE KEY UPDATE other=666;
傳入更新引數值:
INSERT INTO A (a-pk,b-pk,c-pk,other) VALUES (md5(bbcc),bb,cc,666) ON DUPLICATE KEY UPDATE other=VALUES(other);
上面兩條SQL執行後 other 值都為 666,當沒有相同資料執行插入時返回的受影響行數為 1,當相同的時候執行更新操作返回的受影響行數為 2(一條是我們準備插入的,一條是原有更新的)。
2.批量資料插入
單欄位更新:
INSERT INTO `student_course`(`id`, `user_id`, `nc_id`, `nc_user_id`, `nc_commodity_id`, `course_no`, `course_name`, `business_id`)
VALUES
(277941, 11056941, '1001EE1000000043G2T5', '1001EE1000000043G2TO', '1001A5100000003YABO2', 'kckm303', '工業會計實戰V9.0--55', 'kuaiji'),
(277942, 11056941, '1001EE1000000043G2T5', '1001EE1000000043G2TO', '1001A5100000003YABO2', 'kckm303', '工業會計實戰V9.0--66', 'kuaiji'),
(277943, 11056941, '1001EE1000000043G2T5', '1001EE1000000043G2TO', '1001A5100000003YABO2', 'kckm303', '工業會計實戰V9.0--77', 'kuaiji')
ON DUPLICATE KEY UPDATE
course_name = VALUES(course_name);
多欄位更新:
INSERT INTO `student_course`(`id`, `user_id`, `nc_id`, `nc_user_id`, `nc_commodity_id`, `course_no`, `course_name`, `business_id`)
VALUES
(277941, 11056941, '1001EE1000000043G2T5', '1001EE1000000043G2TO', '1001A5100000003YABO2', 'kckm303', '工業會計實戰V9.0--55', 'kuaiji'),
(277942, 11056941, '1001EE1000000043G2T5', '1001EE1000000043G2TO', '1001A5100000003YABO2', 'kckm303', '工業會計實戰V9.0--66', 'kuaiji')
ON DUPLICATE KEY UPDATE
course_name = VALUES(course_name),
business_id = VALUES(business_id);
3.Mybatis中的使用
<insert id="insertBatch" parameterType="java.util.List" >
INSERT INTO bi_log_student_attend (
id, user_plan_id, class_type_id,
compliance_per, creation_time, modified_time
)
VALUES
<foreach collection="list" index="index" item="item" separator="," >
(
#{item.id,jdbcType=VARCHAR},
#{item.userPlanId,jdbcType=BIGINT},
#{item.classTypeId,jdbcType=BIGINT},
#{item.compliancePer,jdbcType=DECIMAL},
#{item.creationTime,jdbcType=TIMESTAMP},
#{item.modifiedTime,jdbcType=TIMESTAMP}
)
</foreach>
ON DUPLICATE KEY UPDATE
compliance_per = VALUES(compliance_per),
modified_time = VALUES(modified_time)
</insert>