【发布时间】:2019-03-25 19:43:40
【问题描述】:
上下文
我正在针对 PostgreSQL 数据库使用 jOOQ。
我想在LEFT OUTER JOIN 的结果集上使用jsonb_object_agg(name, value)。
问题
连接是一个OUTER 之一,有时聚合函数的name 组件只是null:这是行不通的。然后我会去:
COALESCE(
json_object_agg(table.name, table.value) FILTER (WHERE table.name IS NOT NULL),
'{}'
)::json
到目前为止,我用来调用 jsonb_object_agg 的代码(不完全是,但归结为)如下:
public static Field<?> jsonbObjectAgg(final Field<?> key, final Select<?> select) {
return DSL.field("jsonb_object_agg({0}, ({1}))::jsonb", JSON_TYPE, key, select);
}
...JSON_TYPE 是:
private static final DataType<JsonNode> JSON_TYPE = SQLDataType.VARCHAR.asConvertedDataType(/* a custom Converter */);
不完整的解决方案
我很想利用 jOOQ 的 AggregateFilterStep 界面,尤其是能够使用它的 AggregateFilterStep#filterWhere(Condition... conditions)。
但是,implements AggregateFilterStep(间接通过AgregateFunction 和ArrayAggOrderByStep)的org.jooq.impl.Function 类对其package 的可见性受到限制,所以我不能只是盲目地回收DSL#ArrayAggOrderByStep 的实现:
public static <T> ArrayAggOrderByStep<T[]> arrayAgg(Field<T> field) {
return new org.jooq.impl.Function<T[]>(Term.ARRAY_AGG, field.getDataType().getArrayDataType(), nullSafe(field));
}
尝试
我最接近合理的东西是...构建我自己的 coalesceAggregation 函数,专门合并聚合字段:
// Can't quite use AggregateFunction there
// v v
public static <T> Field<T> coalesceAggregation(final Field<T> agg, final Condition coalesceWhen, @NonNull final T coalesceTo) {
return DSL.coalesce(DSL.field("{0} FILTER (WHERE {1})", agg.getType(), agg, coalesceWhen), coalesceTo);
}
public static <T> Field<T> coalesceAggregation(final Field<T> agg, @NonNull final T coalesceTo) {
return coalesceAggregation(agg, agg.isNotNull(), coalesceTo);
}
...但后来我遇到了我的T 类型为JsonNode 的问题,其中DSL#coalesce 似乎是CAST 我的coalesceTo 到varchar。
或者,你知道:
DSL.field("COALESCE(jsonb_object_agg({0}, ({1})) FILTER (WHERE {0} IS NOT NULL), '{}')::jsonb", JSON_TYPE, key, select)
但这将是最后的手段:感觉就像我离让用户将他们想要的任何 SQL 注入我的数据库仅一步之遥????
总之
jOOQ 中是否有办法“正确”实现自己的聚合函数,作为实际的 org.jooq.AgregateFunction?
我想尽可能避免由jooq-codegen 生成它(并不是我不喜欢它——只是我们的管道很糟糕)。
【问题讨论】:
标签: java postgresql jooq