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

ANSI SQL问题-如果记录已经存在,如何插入或更新?,sql,Sql,虽然我现在正在使用mySQL,但我不想要任何特定于DB的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

虽然我现在正在使用mySQL,但我不想要任何特定于DB的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)

这在SQL3中定义为。

使用一对命令:

update test_table inner join test_table lookup 
on test_table.id = lookup.id
and lookup.name = 'bart'
set test_table.colA = ....

插入到测试表中
选择1、'xxx',999
从存在的地方开始

执行此操作的一种方法是简单地执行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)
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;

长期以来,这个操作需要两个单独的命令加上一些框架来处理。因此命名为UPSERT(更新或插入)。但是一些风格的DBMS的最新版本支持更优雅的解决方案

ANSI标准定义了。Oracle自9i版起就支持此功能,MS SQL Server自2005年起就支持此功能。合并语句可能有些冗长

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的语法截然不同

与较旧的SQL标准兼容并因此与更广泛的DBMS兼容的方法(例如,现在的SQLite)是使用:

启用INSERT IF NOT EXISTS语句模拟的:

insert into test_table (id, name, weight) values(1,'pax',72/1.1)
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;

很好的解决方案,可惜很多数据库还不支持此功能:(SQL Server 2005支持合并,Oracle 9i(及更高版本)也支持合并)SQL 2005不支持合并,它是在SQL 2008中引入的否:您也可以在mySql中使用双表。在SQL Server中,如果只需要选择,您可以完全忽略它。我最终使用了INSERT..在重复密钥更新中SQL Server 2005不支持合并语法。只有SQL Server 2008及更高版本支持它。看起来像SQL Server 2005 beta版有,但不是最终版本。2008版有。参考:事实上,我发布这篇文章是为了我自己的参考,因为我拥有的源代码(xaprb.com)在谷歌搜索中不容易找到。:)我喜欢你的解决方案,因为它应该适用于几乎所有的DBMS。但我发现有一点进步。实际上,您不需要互斥表。只需执行一个子选择,使
FROM mutex LEFT JOIN test_table
变为
FROM(选择0作为i)作为mutex LEFT JOIN test_table
,不幸的是,当我尝试时,此修改在HSQLDB上不起作用。不过在Postgresql上工作得很好。