我们在开发数据库相关的逻辑过程中, 经常检查表中是否已经存在这样的一条记录, 如果存在则更新或者不做操作, 如果没有存在记录,则需要插入一条新的记录。
这样的逻辑固然可以通过两条sql语句完成。
SELECT COUNT(*) FROM xxx WHERE ID=xxx; if (x == 0) INSERT INTO xxx VALUES; else UPDATE xxx SET ;
但是这样操作在性能上有所损失, 代码结构感觉有点丑陋。其实Mysql提供了可以在一个SQL语句中完成上述逻辑的支持。
方案一:REPLACE语法
replace的语法格式为:
1. replace into table_name(col_name, …) values(…)
2. replace into table_name(col_name, …) select …
3. replace into table_name set col_name=value, …
算法说明:
REPLACE的运行与INSERT很相像,但是如果旧记录与新记录有相同的值,则在新记录被插入之前,旧记录被删除,即:
1. 尝试把新行插入到表中
2. 当因为对于主键或唯一关键字出现重复关键字错误而造成插入失败时:
从表中删除含有重复关键字值的冲突行
再次尝试把新行插入到表中
旧记录与新记录有相同的值的判断标准就是:表有一个PRIMARY KEY或UNIQUE索引,否则,使用一个REPLACE语句没有意义。
该语句会与INSERT相同,因为没有索引被用于确定是否新行复制了其它的行。
返回值:
REPLACE语句会返回一个数,来指示受影响的行的数目。该数是被删除和被插入的行数的和。
受影响的行数可以容易地确定是否REPLACE只添加了一行,或者是否REPLACE也替换了其它行:检查该数是否为1(添加)或更大(替换)。
示例:
eg:(phone字段为唯一索引)
replace into table_name(email,phone,user_id) values(‘test569′,’99999′,’123′)
另外:在 SQL Server 中可以这样处理:
if not exists (select phone from t where phone= ‘1’)
insert into t(phone, update_time) values(‘1′, getdate())
else
update t set update_time = getdate() where phone= ‘1’
更多信息请看:http://dev.mysql.com/doc/refman/5.1/zh/sql-syntax.html#replace
方案二:ON DUPLICATE KEY UPDATE
如上所写,你也可以在INSERT INTO…..后面加上 ON DUPLICATE KEY UPDATE方法来实现。
如果您指定了ON DUPLICATE KEY UPDATE,并且插入行后会导致在一个UNIQUE索引或PRIMARY KEY中出现重复值,
则执行旧行UPDATE。例如,如果列a被定义为UNIQUE,并且包含值1,则以下两个语句具有相同的效果:
mysql>INSERT INTO table (a,b,c) VALUES (1,2,3)
->ON DUPLICATE KEY UPDATE c=c+1;
mysql>UPDATE table SET c=c+1 WHERE a=1;
如果行作为新记录被插入,则受影响行的值为1;如果原有的记录被更新,则受影响行的值为2。
注释:如果列b也是唯一列,则INSERT与此UPDATE语句相当:
mysql> UPDATE table SET c=c+1 WHERE a=1 OR b=2 LIMIT 1;
如果a=1 OR b=2与多个行向匹配,则只有一个行被更新。通常,您应该尽量避免对带有多个唯一关键字的表使用ON DUPLICATE KEY子句。
您可以在UPDATE子句中使用VALUES(col_name)函数从INSERT…UPDATE语句的INSERT部分引用列值。
换句话说,如果没有发生重复关键字冲突,则UPDATE子句中的VALUES(col_name)可以引用被插入的col_name的值。本函数特别适用于多行插入。VALUES()函数只在INSERT…UPDATE语句中有意义,其它时候会返回NULL。
mysql> INSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6)
-> ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);
本语句与以下两个语句作用相同:
mysql> INSERT INTO table (a,b,c) VALUES (1,2,3)
-> ON DUPLICATE KEY UPDATE c=3;
mysql> INSERT INTO table (a,b,c) VALUES (4,5,6)
-> ON DUPLICATE KEY UPDATE c=9;
当您使用ON DUPLICATE KEY UPDATE时,DELAYED选项被忽略。
示例:
例子1:向一个表里写入数据时,如果没有相关数据就插入,如果有了就更新相关值。
(displayid为主键)
INSERT INTO
cdqsscms_house_hot_top (displayid,x1,x2,x3,x4,x5,last_updated)
VALUES(2820,1,63,79,54,45,1311053750)
ON DUPLICATE KEY UPDATE
x1=x1+ 1,
x2=x2+ 63,
x3=x3+ 79,
x4=x4+ 54,
x5=x5+ 45,
last_updated= 1311053750
例子2(结合 select ..from…):将一个表的数据导入到另外一个表中,数据的重复性就得考虑(如下)。
唯一索引为:email
INSERT INTO table_name1(title,first_name,last_name,email,phone,user_id,role_id,status,campaign_id)
SELECT ”,”,”,table_name2.email,table_name2.phone,NULL,NULL,’pending’,29
FROM table_name2
WHERE table_name2.status = 1
ON DUPLICATE KEY UPDATE table_name1.status = ‘pending’
语句的关键地方,都已高亮出来~
其它关键:DELAYED 做为快速插入,并不是很关心失效性,提高插入性能。
IGNORE 只关注主键对应记录是不存在,无则添加,有则忽略。
特别说明:在MYSQL中UNIQUE 索引将会对null字段失效,也就是说(a字段上建立唯一索引):
insert into test(a) values(null)
insert into test(a) values(null)
比如想往表中插入一条数据,如果表中没有该条数据才插入,如果已经存在该条数据就不插入。
首先,在创建表时,将不需要重复的字段设置为unique,然后在插入时,使用insert ignore语句。
例如:(数据库用的是mysql5)
创建一张表用来存储用户:
create table user_info
(
uid mediumint(10) unsigned NOT NULL auto_increment primary key,
last_name char(20) not null,
first_name char(20) not null,
unique ( last_name, first_name)
);
alter table anser add UNIQUE (last_name,first_name)
插入数据:
insert ignore into user_info (last_name,first_name) values ('x','y');
这样一来,如果表中已经存在last_name='x'且first_name='y'的数据,就不会插入,如果没有就会插入一条新数据。