虽然我正在使用mySQL(目前),但我不想要任何特定于数据库的SQL。
我试图插入一条记录(如果它不存在),并更新一个字段(如果它存在)。我想使用ANSI SQL。
表格如下所示:
create table test_table (id int, name varchar(16), weight double) ;
//test data
insert into test_table (id, name, weight) values(1,'homer', 900);
insert into test_table (id, name, weight) values(2,'marge', 85);
insert into test_table (id, name, weight) values(3,'bart', 25);
insert into test_table (id, name, weight) values(4,'lisa', 15);
If the record exists, I want to update the weight (increase by say 10)
答案 0 :(得分:8)
很长一段时间,这个操作需要两个单独的命令以及一些框架来处理它。因此名称为UPSERT(UPdate或inSERT)。但是最新版本的某些DBMS支持更优雅的解决方案。
ANSI标准定义a MERGE syntax。自9i版本以来,Oracle已经支持这一功能,自2005年以来,它在MS SQL Server中得到了支持.MERGE语句可能有些冗长。
merge into t23
using t42
on t42.id = t23.id
when matched then
update
set t23.col1 = t42.col1
when not matched then
insert (id, col1)
values (t42.id, t42.col1)
/
我认为MERGE语句主要被设想为数据迁移工具,因此其语法要求我们在USING子句中从表中选择数据。我们可以通过从行生成设备(例如Oracle中的dual)中选择文字和伪列来解决此限制。
MySQL的语法不同INSERT ... ON DUPLICATE KEY UPDATE。
答案 1 :(得分:3)
符合旧SQL标准并因此与更广泛的DBMS兼容的方法(例如现在的SQLite,does not support MERGE)是使用a technique involving a mutex table:
CREATE TABLE mutex (i INT);
INSERT INTO mutex VALUES (0);
这样可以模拟 INSERT IF NOT EXISTS 语句:
INSERT INTO test_table (id, name, weight)
SELECT 1, 'homer', 900
FROM mutex LEFT JOIN test_table
ON id = 1
WHERE i = 0 AND id IS NULL;
如果OP的问题是跟随一个简单的更新:
UPDATE test_table SET weight = weight + 10 WHERE id = 1;
答案 2 :(得分:1)
这在SQL3中定义为MERGE
。
答案 3 :(得分:1)
使用UPSERT对命令:
update test_table inner join test_table lookup
on test_table.id = lookup.id
and lookup.name = 'bart'
set test_table.colA = ....
和
insert into test_table
select 1,'xxx', 999
from dual where exists <...>
答案 4 :(得分:0)
执行此操作的一种方法是简单地执行insert和update命令,如果已经有该键的记录,则忽略第一个错误:
try:
insert into test_table (id, name, weight) values(1,'pax',0)
catch (e):
pass
update test_table set weight = weight * 1.1 where id = 1
如果您希望创建的条目的初始权重为(例如)72,请将其用作第一个语句:
insert into test_table (id, name, weight) values(1,'pax',72/1.1)