我们正在使用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();
}
这似乎没有做任何插入,但也没有给出错误,所以我绝对没有什么可以继续。
答案 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 statement
(https://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个无用的行(顺便说一句,它不适用于我的多行常规表之一)
您可能会理解,这更像是解决方法,但总比没有达到目标要好。