【问题标题】:SQL standard UPSERT callSQL 标准 UPSERT 调用
【发布时间】:2013-02-21 12:44:54
【问题描述】:

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

我正在寻找一个有效的、高效的跨平台调用。

我见过MERGEUPSERTREPLACEINSERT .. 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)
);

有什么想法吗?

【问题讨论】:

  • INSERT .. ON DUPLICATE UPDATEmYSQL 中的键。你能显示一些记录或表格结构吗?
  • 是的,但它仅在 MYSQL 中受支持。 HSQLDB 和所有其他人都不使用它...
  • 有一个 ANSI 合并 (en.wikipedia.org/wiki/Merge_%28SQL%29),但并非在所有 DBMS 中都实现。所以没有希望有一个通用的命令。
  • MYSQL 不支持 :(
  • 以防万一您可以使用 ruby​​,我的(警告自我提升)Upsert 库将自动在 mysql 和 postgres 中定义一个可以作为单个命令调用的 upsert 函数。包括广泛的测试。

标签: mysql sql hsqldb upsert


【解决方案1】:

在单个命令中执行 upsert 的语法因 RDBMS 而异。

Wikipedia for more

如果您需要跨平台解决方案,则需要使用多个命令。首先检查现有行,然后根据需要有条件地插入或更新。

【讨论】:

  • 我不想使用多个命令。任何其他想法如何测试和开发将运行相同的代码?
  • 我仍然建议使用条件代码。如果您不这样做,请考虑标准化您的测试和开发环境以使用相同的 RDBMS。
  • @baraky:如果您想支持多个 DBMS,您将永远无法通过在所有 DBMS 上运行的语句来解决所有问题。准备好有 DBMS 特定的语句。其他一切都会失败。
【解决方案2】:

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

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

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


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

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

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

HSQLDB:

CALL DIAGNOSTICS(ROW_COUNT);

MySQL:

SELECT ROW_COUNT();

【讨论】:

  • 或者执行INSERT,捕获SQLException,如果违反完整性约束,执行UPDATE
  • 实际上这(几乎)是我要做的——我要更新,捕获异常(因为更新对我来说很常见),如果失败则插入。谢谢!
猜你喜欢
  • 1970-01-01
  • 2021-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-25
  • 2020-02-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多