英文:
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 ('test', '"key1" => "val1"')
ON CONFLICT (id)
DO UPDATE SET hstore_data = add(t.hstore_data, '"keyX" => "valX"');
add() is a custom function:
CREATE FUNCTION add(hstore, hstore) RETURNS hstore
AS 'select $1 || $2;'
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("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(".*"));
The binding works for hstores, just not for the custom function.
- Are there more clever approaches?
- What might be the reason for add() not being correctly typed?
- 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("java.util.Map<String, String>")
.withBinding("HStoreStringBinding")
.withIncludeTypes("hstore"));
> 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()))
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论