我可以使用MERGE INTO在Apache Derby中模拟“upsert”吗?

时间:2016-01-12 02:32:14

标签: java sql jdbc derby upsert

我们正在使用Derby并且有很多代码如下:

try (ResultSet rs = executeQuery(...)) {
    if (rs.next()) {
        updateRowSet(rs, ...);
        rs.updateRow();
    } else {
        executeUpdate(...);
    }
}

过去,我们一直在寻找一种方法来执行此逻辑服务器端,并发现某些数据库支持“upsert”(更新或插入)操作。 Derby有一个MERGE INTO的功能请求,据说这是SQL:2003标准的做法,所以我们坐着看了票,并且花了很多时间。

Derby 10.11最终添加了MERGE INTO。没有人有时间通过​​并更新代码以使用它,但在阅读他们的文档时,他们的所有示例都显示从一个表合并到另一个表。但请继续,我们的数据还不在表中!

我知道我可以放在一个表中,但之后再次出现多次查询,这完全违背了使用它的目的。

我确信有可能没有将它放入表中,但由于文档没有显示单个示例,我不知道如何继续。

以下是我一直在尝试的内容:

try (PreparedStatement ps = connection.prepareStatement(
        "MERGE INTO things AS target " +
        // Awkward point 1:
        // It wants a "source" table, but I don't have one.
        // So I thought I would try to use the same table with
        // another name.
        "  USING things AS source ON target.id = ?" +
        "  WHEN MATCHED THEN" +
        "    UPDATE SET data = ?" +
        "  WHEN NOT MATCHED THEN" +
        "    INSERT (id, data) VALUES (??, ?)"))
{
    ps.setLong(1, id);
    ps.setBinaryStream(2, data);
    ps.setLong(3, id);
    // Awkward point 2:
    // Passing an InputStream into a query as two
    // parameters.
    ps.setBinaryStream(4, data);
    ps.execute();
}

这似乎没有做任何插入,但也没有给出错误,所以我绝对没有什么可以继续。

2 个答案:

答案 0 :(得分:2)

以下适用于Apache Derby 10.12.1.1:

merge into FOO
using RANDOM_TABLE
on FOO.guid = 'qwerty'
when matched then
    update set guid = 'qwerty'
when not matched then
    insert (guid) values('qwerty')       

这里FOO是我要进行upsert的目标表,RANDOM_TABLE是我数据库中的任何其他表。值'qwerty'是我的数据和唯一键。在这个示例中,FOO只有一个列,但它应该只是为插入添加更多列并分别更新。

我发现这种语法非常不优雅,但至少它确实似乎避免执行两个单独的语句来完成这项工作。

答案 1 :(得分:2)

为仍然使用德比的所有可悲的人共享它:) 因此,我通过merge into statementhttps://db.apache.org/derby/docs/10.14/ref/rrefsqljmerge.html)的方式解决了该问题:

MERGE INTO foo
USING SYSIBM.SYSDUMMY1
ON foo.id = '1' AND foo.language = 'en'
WHEN MATCHED THEN
  UPDATE SET name = 'name2', image = 'someImgUrl2'
WHEN NOT MATCHED THEN
  INSERT (id, name, language, image)
  VALUES ('1', 'name1', 'en', 'someImgUrl1')

其中foo是您要在其中更新行的表,而SYSIBM.SYSDUMMY1德比虚拟表仅具有1个无用的行(顺便说一句,它不适用于我的多行常规表之一)

您可能会理解,这更像是解决方法,但总比没有达到目标要好。