【问题标题】:Portable SQL upsert (insert+update) solution needed需要便携式 SQL upsert(插入+更新)解决方案
【发布时间】:2011-05-28 14:11:42
【问题描述】:

我需要对数据库执行一个非常简单的操作 - 将一些值按键放入表中,如果该行存在 - 更新它,如果不存在 - 创建一个新的。问题是我需要以可移植的方式进行 - 即相同的查询必须适用于 MySQL、SQL Server、Oracle,最好还适用于 DB2、Postgres 等。所以虽然我可以在 MySQL 中使用 REPLACEINSERT ... ON DUPLICATE KEY UPDATE ,我不确定这些是否支持这种语法。而且我真的想避免使用数据库类型的 if,因为这将是不可维护的。我也不想在更新之前实际查询该值,因为我怀疑它会显着减慢进程(我需要多次执行)。

到目前为止,我想出的最好的方法就是:

  UPDATE table SET data='data' WHERE key='key';
  INSERT INTO table(key, data) VALUES ('key', 'data');

其中一个总是成功而另一个失败,但我不在乎其中一个查询失败。不过看起来有点不雅。有什么建议可以让它变得更好吗?

【问题讨论】:

    标签: sql mysql sql-server database oracle


    【解决方案1】:

    首先执行UPDATE。您的客户端代码将被告知更新的行数。如果更新的行数为零,则执行INSERT

    更新的行数返回到客户端代码的确切方式取决于您使用的数据库访问库。例如,在 Java 中它是 PreparedStatement.executeUpdate() 的返回值,而在 Python DB-API 中它是使用 cursor.rowcount 访问的。

    您需要确保整个过程发生在可序列化事务中,以避免与并发写入者发生冲突。

    【讨论】:

    • 是的,看起来受影响的行数是普遍支持的,所以我可以让它足够便携,谢谢。
    • 这里有一个问题 - 如果值存在,mysql 似乎会返回 0 行受影响的行,但设置为与已有的值相同的值。
    • 很公平。现在... 我把那张 80 年代精选专辑放在哪里了? :)
    【解决方案2】:

    MERGE 和 WHEN NOT MATCHED 是 ANSI SQL 2003 的一部分。当然,除了它没有得到统一支持。

    您的解决方案虽然聪明但很危险,因为它不清楚客户应该做什么。忽略所有错误?如果是这样,如果他们都失败了,会发生什么。

    相反,不要试图让这个便携。使用存储过程和/或 DAL 来处理后端之间的差异,因为无论如何这无疑不是您唯一的问题。

    【讨论】:

    • 客户端会忽略这些语句中的错误。如果他们都失败了,那没什么大不了的,尽管这当然是不雅的部分。不幸的是,存储过程在这里不是一个选项......
    【解决方案3】:

    使用现代数据库的唯一完全与数据库无关的解决方案是在两个操作中调用更新然后插入。有些数据库不允许在单个操作中发送多个语句,有些数据库可能不会返回受更新影响的行数,所以我不会依赖它。

    Update MyTable
    Set Data = 'Data'
    Where KeyCol = 'key';
    

    (单独调用)

    Insert Into MyTable(KeyCol, Data)
    Select 'key', 'Data'
    From ( Select 1 As Value ) As Z
    Where Not Exists    (
                        Select 1
                        From MyTable As T1
                        Where T1.KeyCol = 'key'
                        );
    

    【讨论】:

    • 我上一次遇到没有返回受影响行数的数据库是在 80 年代 ;) 但是,您的解决方案是一个不错的选择。
    • @WReach - 是的,但 OP 并没有明确说明解决方案需要如何与数据库无关。 :)
    • 我知道@StasM 提到他们不想“在更新之前查询值,因为我怀疑它会减慢进程”,但如果我不这样做,这不是一个可行的选择有这样的性能问题。这种方法还有其他我应该知道的缺点吗?
    • 这是一个可行的选择。大多数数据库产品会让您在更新选项后检查行数,这会告诉您是否可以跳过插入操作。还有其他特定于供应商的选项,例如 SQL Server 中的 Merge 命令,如果您可以使用特定于供应商的解决方案,它会提供一些替代方案。
    猜你喜欢
    • 2015-04-06
    • 1970-01-01
    • 1970-01-01
    • 2019-09-21
    • 1970-01-01
    • 1970-01-01
    • 2016-04-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多