8

我正在寻找一个标准的 SQL " UPSERT" 语句。如果存在,则一次调用插入和更新。

我正在寻找一个工作,高效和跨平台的电话。

我见过MERGE, UPSERT, REPLACEINSERT .. ON DUPLICATE UPDATE但没有任何语句满足需求。

顺便说一句,我使用 MYSQL 和 HSQLDB 进行单元测试。我知道 HSQLDB 是有限的,可能无法满足我的需求,但即使没有它,我也找不到标准的方法。一个只有 MYSQL 和 HSQLDB 的语句现在也足够了。

我一直在四处寻找,但无法得到答案。

我的桌子:

CREATE TABLE MY_TABLE (
  MY_KEY varchar(50) NOT NULL ,
  MY_VALUE varchar(50) DEFAULT NULL,
  TIME_STAMP bigint NOT NULL,
  PRIMARY KEY (MY_KEY)
);

任何想法?

4

2 回答 2

6

MySQL 和 HSQLDB 都支持的唯一解决方案是查询您打算替换的行,并且有条件地是 INSERT 或 UPDATE。这意味着您必须编写更多的应用程序代码来补偿 RDBMS 实现之间的差异。

  1. 开始交易。
  2. 选择...更新。
  3. 如果 SELECT 找到行,则 UPDATE。
  4. 否则,插入。
  5. 犯罪。

MySQL 不支持 ANSI SQL MERGE 语句。它支持 REPLACE 和 INSERT...ON DUPLICATE KEY UPDATE。有关更多信息,请参阅我对“INSERT IGNORE”与“INSERT ... ON DUPLICATE KEY UPDATE”的回答。


回复评论:是的,另一种方法是尝试 INSERT 并查看它是否成功。否则,请执行 UPDATE。如果您尝试 INSERT 并遇到重复键,则会生成错误,这会在某些客户端界面中变成异常。在 MySQL 中这样做的缺点是,即使 INSERT 失败,它也会生成一个新的自动增量 ID。所以你最终会出现差距。我知道自动增量序列中的间隙通常不用担心,但我去年帮助了一位客户,由于这种影响,成功插入之间的间隙为 1000-1500,结果是他们用尽了INT 在他们的主键中。

正如@baraky 所说,可以改为先尝试 UPDATE ,如果这影响零行,则改为执行 INSERT 。我对这个策略的评论是更新零行也不例外——你必须在更新之后检查“受影响的行数”才能知道它是否“成功”。

但是查询受影响的行数会让您回到最初的问题:您必须在 MySQL 和 HSQLDB 中使用不同的查询。

数据库:

CALL DIAGNOSTICS(ROW_COUNT);

MySQL:

SELECT ROW_COUNT();
于 2013-03-06T16:28:31.317 回答
6
于 2013-03-06T16:10:19.257 回答