在使用jOOQ进行hstore合并时出现重复键

huangapple go评论83阅读模式
英文:

On duplicate key with hstore merge using jooq

问题

以下是翻译好的内容:

目前我正在尝试在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(".*"));
绑定适用于hstore只是不适用于自定义函数

1. 有没有更聪明的方法
2. *add()* 函数无法正确匹配的原因是什么
3. 如何告诉jooq在合并操作中使用原始值就像我在原始SQL查询中使用t.hstore_data一样
英文:

Currently, I'm trying to implement the following sql query in jooq:

INSERT INTO table as t (id, hstore_data) 
VALUES (&#39;test&#39;, &#39;&quot;key1&quot; =&gt; &quot;val1&quot;&#39;) 
ON CONFLICT (id) 
DO UPDATE SET hstore_data = add(t.hstore_data, &#39;&quot;keyX&quot; =&gt; &quot;valX&quot;&#39;);

add() is a custom function:

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

So far, I managed to get this up and running:

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() is a simple JAVA function merging two maps.

This approach works. However, I'd like to do all the processing on the database server as the first query suggests.

I tried to use the routine that jooq generates for add(). But it seems like jooq does not use the hstore binding. The binding is defined in the ConfigGenerator as follows:

types.add(new ForcedType()
.withUserType(&quot;java.util.Map&lt;String, String&gt;&quot;)
.withBinding(&quot;HStoreStringBinding&quot;)
.withIncludeExpression(&quot;.*_data&quot;)
.withIncludeTypes(&quot;.*&quot;));
types.add(new ForcedType()
.withUserType(&quot;java.util.Map&lt;String, Long&gt;&quot;)
.withBinding(&quot;HStoreLongBinding&quot;)
.withIncludeExpression(&quot;.*_counts&quot;)
.withIncludeTypes(&quot;.*&quot;));

The binding works for hstores, just not for the custom function.

  1. Are there more clever approaches?
  2. What might be the reason for add() not being correctly typed?
  3. How can I tell jooq to use the original value in the merge as I do in the raw SQL query with t.hstore_data?

答案1

得分: 1

// add() 未正确类型化的原因可能是什么?

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

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

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

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

set(TABLE.HSTORE_DATA, Routines.add(TABLE.HSTORE_DATA, table.getHstoreData()))
英文:

> What might be the reason for add() not being correctly typed?

Try naming your function parameters, otherwise you cannot match them with the includeExpression property. To match the return value of the function, use the function name itself as an includeExpression. Of course, you could just leave the property away, and match all hstore types with a more generic binding:

types.add(new ForcedType()
            .withUserType(&quot;java.util.Map&lt;String, String&gt;&quot;)
            .withBinding(&quot;HStoreStringBinding&quot;)
            .withIncludeTypes(&quot;hstore&quot;));

> How can I tell jooq to use the original value in the merge as I do in the raw SQL query with t.hstore_data?

Once code generation works, you just use your add function, just like in the SQL version of your statement:

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

huangapple
  • 本文由 发表于 2020年4月7日 16:22:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/61075716.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定