【问题标题】:On duplicate key with hstore merge using jooq在使用 jooq 与 hstore 合并的重复键上
【发布时间】:2020-07-19 09:22:39
【问题描述】:

目前,我正在尝试在 jooq 中实现以下 sql 查询:

INSERT INTO table as t (id, hstore_data) 
VALUES ('test', '"key1" => "val1"') 
ON CONFLICT (id) 
DO UPDATE SET hstore_data = add(t.hstore_data, '"keyX" => "valX"');

add() 是一个自定义函数:

CREATE FUNCTION add(hstore, hstore) RETURNS hstore
AS 'select $1 || $2;'
LANGUAGE SQL
IMMUTABLE
RETURNS NULL ON NULL INPUT;

到目前为止,我已成功启动并运行它:

return DSL.using(configuration)
            .insertInto(TABLE)
            .columns(TABLE.ID, TABLE.HSTORE_DATA)
            .values(table.getId(), table.getHstoreData())
            .onDuplicateKeyUpdate()
            .set(TABLE.HSTORE_DATA,
                            merge(
                                    DSL.using(configuration).select(TABLE.HSTORE_DATA).from(TABLE).where(TABLE.ID.eq(table.getId())).fetchAnyInto(HashMap.class)
                                    , table.getHstoreData()

                            )
                    )
            .execute();

merge() 是一个简单的 JAVA 函数,合并两个地图。

这种方法有效。但是,我想按照第一个查询的建议在数据库服务器上进行所有处理。

我尝试使用 jooq 为 add() 生成的例程。但似乎 jooq 不使用 hstore 绑定。绑定在 ConfigGenerator 中定义如下:

types.add(new ForcedType()
            .withUserType("java.util.Map<String, String>")
            .withBinding("HStoreStringBinding")
            .withIncludeExpression(".*_data")
            .withIncludeTypes(".*"));
types.add(new ForcedType()
            .withUserType("java.util.Map<String, Long>")
            .withBinding("HStoreLongBinding")
            .withIncludeExpression(".*_counts")
            .withIncludeTypes(".*"));

绑定适用于 hstores,但不适用于自定义函数。

  1. 还有更聪明的方法吗?
  2. add() 输入不正确的原因可能是什么?
  3. 如何告诉 jooq 在合并中使用原始值,就像在原始 SQL 查询中使用 t.hstore_data 一样?

【问题讨论】:

  • 不相关,但是:您实际上不需要定义自己的 add() 函数。您可以简单地使用hs_concat(),它是hstore 的|| 运算符的实现。
  • @a_horse_with_no_name 确实,我曾经想过尝试,但又忘记了。谢谢!

标签: java sql postgresql jooq


【解决方案1】:

add() 输入不正确的原因可能是什么?

尝试命名函数参数,否则无法将它们与includeExpression 属性匹配。要匹配函数的返回值,请将函数名称本身用作includeExpression。当然,您可以不使用该属性,并使用更通用的绑定匹配所有 hstore 类型:

types.add(new ForcedType()
            .withUserType("java.util.Map<String, String>")
            .withBinding("HStoreStringBinding")
            .withIncludeTypes("hstore"));

我如何告诉 jooq 在合并中使用原始值,就像我在使用 t.hstore_data 的原始 SQL 查询中所做的那样?

一旦代码生成工作,您只需使用您的 add 函数,就像在您的语句的 SQL 版本中一样:

set(TABLE.HSTORE_DATA, Routines.add(TABLE.HSTORE_DATA, table.getHstoreData()))

【讨论】:

  • 这似乎可行,谢谢!我只需要交换 ForcedTypes 的顺序还有一件事:当我应用您对 set(...) 的建议时,参数会发生冲突。 TABLE.HSTORE_DATA 是一个记录,而函数需要一个地图
  • @fabianski: “我也只需要交换 ForcedTypes 的顺序” - 第一个匹配项适用。 “TABLE.HSTORE_DATA 是一条记录” - 为什么现在是一条记录?您已为所有 ".*_data" 列应用了第一个强制类型。你改了吗?
  • 啊,是的,我必须改变一些东西,因为我想尝试离开财产。但是,这会产生错误,因为 Map 在某些地方是必需的。所以通过为了匹配函数的返回值,使用函数名本身作为includeExpression。我理解做类似.withIncludeExpression(".*_data | add")的事情。你是那个意思吗?因为它仍然与打字不匹配:(
  • @fabianski:Map&lt;String, String&gt;Map&lt;String, Long&gt; 在 Java 中是不兼容的类型。这听起来像是一个新问题,其中包含为什么您首先需要 Map&lt;String, Long&gt; 的附加信息。
  • 是的,你是对的。在这个地方我不需要 Map。但在其他地方,我将不同标签的数量存储在一个对象中。使用 Map 而不是 Map 可以简化一些事情。这就是我在 *_data 和 *_counts 之间存在差异的原因
猜你喜欢
  • 2015-03-07
  • 2019-03-18
  • 1970-01-01
  • 1970-01-01
  • 2019-05-06
  • 1970-01-01
  • 2015-03-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多