如何在JOOQ的listAgg函数中使用distinct关键字适配Oracle语法
解决方案
方案1:使用高版本JOOQ原生API(推荐)
JOOQ 3.15及以上版本已经正式开放了LISTAGG的distinct支持,提供了listAggDistinct()方法直接生成带DISTINCT关键字的聚合语句,不需要访问内部私有类。
代码示例:
create.selectDistinct(DATA.asterisk(), listAggDistinct(ORGANISATIONS.LABEL, ", ") .withinGroupOrderBy(DATA.ID) .as("ORG_LABELS")) .from(DATA) .join(ORGANISATIONS).on(DATA.ORG_ID.eq(ORGANISATIONS.ID)) .groupBy(DATA.fields()) .fetch();
方案2:低版本JOOQ使用纯SQL片段实现
如果使用的JOOQ版本低于3.15,最稳妥的方式是通过DSL.field()构造自定义SQL片段,避免依赖JOOQ内部非公开API,兼容性最好。
代码示例:
// 构造带DISTINCT的LISTAGG聚合函数片段 Field<String> orgLabels = DSL.field( "LISTAGG(DISTINCT {0}, ', ') WITHIN GROUP (ORDER BY {1})", String.class, ORGANISATIONS.LABEL, DATA.ID ).as("ORG_LABELS"); create.selectDistinct(DATA.asterisk(), orgLabels) .from(DATA) .join(ORGANISATIONS).on(DATA.ORG_ID.eq(ORGANISATIONS.ID)) .groupBy(DATA.fields()) .fetch();
方案3:逻辑层先去重再聚合
如果不想写任何原生SQL片段,可以先通过子查询提前对关联的ORGANISATIONS数据去重,再执行聚合,逻辑上和带DISTINCT的LISTAGG效果一致:
代码示例:
// 先构造去重后的关联数据子查询 Table<?> subQuery = create.select(DATA.fields()) .select(ORGANISATIONS.LABEL) .from(DATA) .join(ORGANISATIONS).on(DATA.ORG_ID.eq(ORGANISATIONS.ID)) .distinct() .as("t"); // 基于子查询做聚合,此时不需要DISTINCT也能达到去重效果 create.select(subQuery.fields(DATA.fields())) .select(listAgg(subQuery.field(ORGANISATIONS.LABEL), ", ") .withinGroupOrderBy(subQuery.field(DATA.ID)) .as("ORG_LABELS")) .from(subQuery) .groupBy(subQuery.fields(DATA.fields())) .fetch();
注意:不建议通过反射修改JOOQ内部ListAgg对象的私有标识位,这种方式依赖内部实现,JOOQ版本升级后很容易出现兼容性问题。
内容的提问来源于stack exchange,提问作者Remo
相关产品推荐
相关产品推荐

