insert...on?duplicate?key?update語(yǔ)法詳解
一.作用和使用場(chǎng)景
在mysql入庫(kù)時(shí),不能出現(xiàn)兩條數(shù)據(jù)主鍵一致的情況,因?yàn)樵趦蓷l數(shù)據(jù)的主鍵一致的情況下,mysql就會(huì)判定為待插入數(shù)據(jù)在數(shù)據(jù)庫(kù)中存在重復(fù)數(shù)據(jù),也就是說(shuō)判斷數(shù)據(jù)是否重復(fù)是根據(jù)主鍵來(lái)區(qū)別的。
但是有一些場(chǎng)景,如日志文件解析入庫(kù),消息隊(duì)列接收數(shù)據(jù)入庫(kù)等情況下可能解析到或者接收到待插入的重復(fù)數(shù)據(jù)存在重復(fù)數(shù)據(jù)則更新,不存在則插入。
這時(shí)如下語(yǔ)句的寫(xiě)法就派上用場(chǎng)了,on duplicate key update的作用也就是說(shuō)存在重復(fù)數(shù)據(jù)則更新,不存在則插入。
二.例子詳細(xì)講解
場(chǎng)景大概是這樣的,業(yè)務(wù)方的需求是查詢一條語(yǔ)句在不在,如果在就給出一個(gè)update語(yǔ)句,更新這條記錄,如果不在,就給出一個(gè)insert語(yǔ)句,插入這條記錄。邏輯大概是:
result = select * from table; if result = 0 insert the record into table; else update the record;
這樣的操作乍一看沒(méi)有什么問(wèn)題,但是仔細(xì)分析分析,還是有些瓶頸的,目前來(lái)看,我能分析到的瓶頸有兩個(gè),
其一:
每次要執(zhí)行2個(gè)SQL,效率比較差;
其二:
當(dāng)我們?cè)诟卟l(fā)的情況下跑這條語(yǔ)句,如果程序崩潰,不能保證操作的原子性。
說(shuō)明: 1. on duplicate key update 含義: 1)如果在INSERT語(yǔ)句末尾指定了 on duplicate key update, 并且插入行后會(huì)導(dǎo)致在一個(gè)UNIQUE索引或PRIMARY KEY中出現(xiàn)重復(fù)值, 則在出現(xiàn)重復(fù)值的行執(zhí)行UPDATE; 2)如果不會(huì)導(dǎo)致唯一值列重復(fù)的問(wèn)題,則插入新行。 2. values(col_name)函數(shù)只是取當(dāng)前插入語(yǔ)句中的插入值,并沒(méi)有累加功能。 如:count = values(count) 取前面 insert into 中的 count 值,并更新 當(dāng)有多條記錄沖突,需要插入時(shí),前面的更新值都被最后一條記錄覆蓋, 所以呈現(xiàn)出取最后一條更新的現(xiàn)象。 如:count = count + values(count) 依然取前面 insert into 中的 count 值, 并與原記錄值相加后更新回?cái)?shù)據(jù)庫(kù),這樣,當(dāng)多條記錄沖突需要插入時(shí), 就實(shí)現(xiàn)了不斷累加更新的現(xiàn)象。 注:insert into ... on duplicate key update ... values() 這個(gè)語(yǔ)句 盡管在沖突時(shí)執(zhí)行了更新,并沒(méi)有插入,但是發(fā)現(xiàn)依然會(huì)占用 id 序號(hào)(自增), 出現(xiàn)很多丟失的 id 值,可參看下面案例
函數(shù)使用說(shuō)明:在一個(gè) INSERT … ON DUPLICATE KEY UPDATE … 語(yǔ)句中,你可以在 UPDATE 子句中使用 VALUES(col_name ) 函數(shù),用來(lái)訪問(wèn)來(lái)自該語(yǔ)句的 INSERT 部分的列值。換言之,UPDATE 子句中的 VALUES(col_name ) 訪問(wèn)需要被插入的 col_name 的值 , 并不會(huì)發(fā)生重復(fù)鍵沖突。這個(gè)函數(shù)在多行插入中特別有用。 VALUES() 函數(shù)只在 INSERT ... UPDATE 語(yǔ)句中有意義,而在其它情況下只會(huì)返回 NULL。
**案例: 0. 創(chuàng)建案例表 word_count_0626(單詞計(jì)數(shù)表) use test; CREATE TABLE IF NOT EXISTS word_count_0626 ( id int(11) NOT NULL AUTO_INCREMENT, word varchar(64) NOT NULL, count int(11) DEFAULT 0, date date NOT NULL, PRIMARY KEY (id), UNIQUE KEY word (word, date) // (word,date) 兩字段組合唯一 ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 注:curdate() 為 "2019-06-26" 1. 執(zhí)行第一次:(首次數(shù)據(jù)庫(kù)表中沒(méi)有數(shù)據(jù),正常插入) insert into word_count_0626 (word, count, date) values ('a',5,curdate()) on duplicate key update count=values(count); # 結(jié)果顯示: id word count date 1 a 5 2019-06-26 2. 執(zhí)行第二次:(與第一次的唯一(word,date)沖突,執(zhí)行更新) insert into word_count_0626 (word, count, date) values ('a',6,curdate()) on duplicate key update count=values(count); # 結(jié)果顯示: id word count date 1 a 6 2019-06-26 (更新) 3. 執(zhí)行第三次: insert into word_count_0626 (word, count, date) values ('a',6,curdate()-1), // 取前一天,不會(huì)沖突 ('a',7,curdate()) // 沖突 on duplicate key update count=values(count); # 結(jié)果顯示: id word count date 1 a 7 2019-06-26 (更新) 3 a 6 2019-06-25 (新插入) 4. 執(zhí)行第四次:(更新沖突的最后一條插入值) insert into word_count_0626 (word, count, date) values ('a',2,curdate()), // 沖突 ('a',1,curdate()) // 沖突 on duplicate key update count=values(count); # 結(jié)果顯示: id word count date 1 a 1 2019-06-26 (更新最后一條插入值) 3 a 6 2019-06-25 (不變) 5. 執(zhí)行第五次:(更新沖突的累加插入值) insert into word_count_0626 (word, count, date) values ('a',2,curdate()), ('a',1,curdate()) on duplicate key update count=count+values(count); // 實(shí)現(xiàn)每行累加 # 結(jié)果顯示: id word count date 1 a 4 2019-06-26 3 a 6 2019-06-25 6. 執(zhí)行第六次:(無(wú)沖突插入,觀察 id 鍵值,出現(xiàn)了很多丟失,id 直接跳到了 9) insert into word_count_0626 (word, count, date) values ('b',2,curdate()) on duplicate key update count=count+values(count); # 結(jié)果顯示: id word count date 1 a 4 2019-06-26 3 a 6 2019-06-25 9 b 2 2019-06-26
說(shuō)明:
insert...on duplicate key方法
簡(jiǎn)單寫(xiě)一個(gè)例子,內(nèi)容大致如下:
1、首先創(chuàng)建一個(gè)包含id,name,age的表,其中id是主鍵;
2、在這個(gè)表中插入一條id=1的記錄;
3、使用insert...on duplicate key update語(yǔ)法插入一條id=2的記錄;
4、使用同樣的語(yǔ)法更新id=1的記錄;
mysql 23:12:32>>create table test_1( -> id int primary key auto_increment, -> name varchar(20), -> age int not null -> ) engine=innodb charset=utf8; Query OK, 0 rows affected (0.08 sec) mysql 23:13:26>>insert into test_1 values (1,'yyz',16); Query OK, 1 row affected (0.01 sec) mysql 23:13:58>>select * from test_1; +----+------+-----+ | id | name | age | +----+------+-----+ | 1 | yyz | 16 | +----+------+-----+ 1 row in set (0.00 sec) mysql 23:14:36>>insert into test_1 (id,name,age) values (2,'yyz',18) on duplicate key update age=18; Query OK, 1 row affected (0.01 sec) mysql 23:15:08>>select * from test_1; +----+------+-----+ | id | name | age | +----+------+-----+ | 1 | yyz | 16 | | 2 | yyz | 18 | +----+------+-----+ 2 rows in set (0.00 sec) mysql 23:15:17>>insert into test_1 (id,name,age) values (1,'yyz',18) on duplicate key update age=18; Query OK, 2 rows affected (0.00 sec) mysql 23:15:28>>select * from test_1; +----+------+-----+ | id | name | age | +----+------+-----+ | 1 | yyz | 18 | | 2 | yyz | 18 | +----+------+-----+ 2 rows in set (0.00 sec)
insert...on duplicate key update語(yǔ)法的作用,可以分析到,當(dāng)發(fā)生主鍵沖突的時(shí)候,可以直接進(jìn)行update操作,這個(gè)update操作里面可以更新任意想要更新的列;而沒(méi)有主鍵沖突的時(shí)候,相當(dāng)于對(duì)這個(gè)表進(jìn)行了一次插入操作。
Replace操作
Replace語(yǔ)句。使用Replace插入一條記錄時(shí),如果不重復(fù),Replace就和Insert的功能一樣,如果有重復(fù)記錄,Replace就使用新記錄的值來(lái)替換原來(lái)的記錄值。
使用REPLACE的最大好處就是可以將Delete和Insert合二為一,形成一個(gè)原子操作。這樣就可以不必考慮在同時(shí)使用Delete和Insert時(shí)添加事務(wù)等復(fù)雜操作了。
在使用Replace時(shí),表中必須有唯一索引,而且這個(gè)索引所在的字段不能允許空值,否則Replace就和Insert完全一樣的。
在執(zhí)行Replace后,系統(tǒng)返回了所影響的行數(shù),如果返回1,說(shuō)明在表中并沒(méi)有重復(fù)的記錄,如果返回2,說(shuō)明有一條重復(fù)記錄,系統(tǒng)自動(dòng)先調(diào)用了Delete刪除這條記錄,然后再記錄用Insert來(lái)插入這條記錄。
不同之處
有了上面的知識(shí)儲(chǔ)備,這兩條命令的不同之處就顯而易見(jiàn)了,replace是刪除記錄,然后再重新insert,而insert...on duplicate key update是直接在該條記錄上修改,所以二者的差別主要有以下兩處:
1、當(dāng)表中存在自增值的時(shí)候,如果表中存在某條記錄,replace語(yǔ)法會(huì)導(dǎo)致自增值+1,而insert...on duplicate key update語(yǔ)法不會(huì);
2、當(dāng)表中的某些字段中包含默認(rèn)值的時(shí)候,replace操作插入不完全字段的記錄,會(huì)導(dǎo)致其他字段直接使用默認(rèn)值,而insert...on duplicate key update操作會(huì)保留該條記錄的原有值。
到此這篇關(guān)于insert...on duplicate key update語(yǔ)法詳解的文章就介紹到這了,更多相關(guān)insert...on duplicate key update 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- mysql 中 replace into 與 insert into on duplicate key update 的用法和不同點(diǎn)實(shí)例分析
- MySQL的Replace into 與Insert into on duplicate key update真正的不同之處
- insert into … on duplicate key update / replace into 多行數(shù)據(jù)介紹
- Mysql中Insert into xxx on duplicate key update問(wèn)題
- mysql insert的幾點(diǎn)操作(DELAYED,IGNORE,ON DUPLICATE KEY UPDATE )
相關(guān)文章
簡(jiǎn)單了解MySQL數(shù)據(jù)庫(kù)優(yōu)化技巧
這篇文章主要介紹了簡(jiǎn)單了解MySQL數(shù)據(jù)庫(kù)優(yōu)化技巧,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07Slave memory leak and trigger oom-killer
這篇文章主要介紹了Slave memory leak and trigger oom-killer,需要的朋友可以參考下2016-07-07MySQL查詢優(yōu)化:LIMIT 1避免全表掃描提高查詢效率
在某些情況下,如果明知道查詢結(jié)果只有一個(gè),SQL語(yǔ)句中使用LIMIT 1會(huì)提高查詢效率,感興趣的朋友可以了解下哈,希望對(duì)你優(yōu)化mysql查詢有所幫助2013-04-04經(jīng)測(cè)試最好用的mysql密碼忘記的解決方法
經(jīng)測(cè)試最好用的mysql密碼忘記的解決方法...2007-06-06mysql 5.7.21解壓版安裝配置方法圖文教程(win10)
這篇文章主要為大家詳細(xì)介紹了win10下mysql 5.7.21解壓版安裝配置方法圖文教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-02-02mysql中l(wèi)imit查詢踩坑實(shí)戰(zhàn)記錄
在MySQL中我們常常用order by來(lái)進(jìn)行排序,使用limit來(lái)進(jìn)行分頁(yè),下面這篇文章主要給大家介紹了關(guān)于mysql中l(wèi)imit查詢踩坑的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-03-03MYSQL大量寫(xiě)入問(wèn)題優(yōu)化詳解
這篇文章主要介紹了MYSQL大量寫(xiě)入問(wèn)題優(yōu)化詳解,文中優(yōu)化點(diǎn)解釋的很清楚,讓人看完就明了,感興趣的同學(xué)可以閱讀理解下2021-03-03