我尝试使用jOOQ创建类似于arrayRemove的函数,但允许从uuid[]
类型的PostgreSQL列中一次删除多个元素。
所以我的第一次尝试是:
private Field<UUID[]> arrayRemoveAll(final Field<UUID[]> field, final Set<UUID> elements) {
return select(field("array_agg(tab.col)", UUID[].class))
.from(unnest(field).as("tab", "col"))
.where(field("tab.col", UUID.class).notIn(elements))
.asField();
}
成功删除每个请求的元素,但如果我尝试删除每个元素,则会出现返回null
而不是空数组的问题。
所以我在我的代码中添加了一个coalesce,使它返回一个空数组:
private Field<UUID[]> arrayRemoveAll(final Field<UUID[]> field, final Set<UUID> elements) {
final Field<UUID[]> newArray = select(field("array_agg(tab.col)", UUID[].class))
.from(unnest(field).as("tab", "col"))
.where(field("tab.col", UUID.class).notIn(elements))
.asField();
return coalesce(newArray, field("{}", UUID[].class));
}
但是运行此代码会抛出此异常:
org.jooq.exception.DataAccessException: SQL [<<confidential SQL removed>>]
Caused by: org.postgresql.util.PSQLException: ERROR: syntax error at or near ")"
这是它抱怨的SQL异常的一部分(注意尾随的逗号和coalesce
中缺少第二个参数):
coalesce((select array_agg(tab.col)
from unnest("my_schema"."my_table"."my_field") as "tab"("col")
where tab.col not in (?, ?)), )
这是jOOQ中的错误吗?
答案 0 :(得分:2)
我发现上面的代码中混合了field
和val
,将field("{}", UUID[].class)
更改为val(new UUID[0])
可以解决问题。
另请查看Lukas Eder关于如何使用field
解决问题的答案。
所以带有泛型的最终代码看起来像这样:
private <T> Field<T[]> arrayRemoveAll(final Field<T[]> field, final Set<T> elements, final T[] emptyArray) {
final Field<T[]> newArray = select(field("array_agg(tab.col)"))
.from(unnest(field).as("tab", "col"))
.where(field("tab.col").notIn(elements))
.asField();
return coalesce(newArray, val(emptyArray));
}
你可以在你的陈述中使用它:
using(configuration)
.update(MY_TABLE)
.set(MY_TABLE.MY_COLUMN,
arrayRemoveAll(MY_TABLE.MY_COLUMN, someElements, new UUID[0]))
.where(MY_TABLE.ID.eq(...))
.execute();
答案 1 :(得分:1)
你的field("{}")
没有在SQL中生成{}
字符串,但被认为是jOOQ的纯SQL模板语言的一部分,遗憾的是它不允许转义那些括号:
https://www.jooq.org/doc/latest/manual/sql-building/plain-sql-templating
幸运的是,PostgreSQL支持更正式,符合标准的方法来创建一个空数组文字:
field("array[]::uuid[]", UUID.class)