ANSI SQL问题 - 如果记录已存在,如何插入或更新记录?

时间:2010-04-18 13:48:43

标签: sql

虽然我正在使用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)

5 个答案:

答案 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)