jOOQ-在“ when”查询中从“ then”返回字段元组

时间:2019-07-15 15:16:02

标签: java sql postgresql jooq

我将jOOQ与PostgreSQL一起使用,并且尝试使用CASE WHEN创建一个具有多个计数的选择查询。因为仅计数唯一记录很重要,所以我也使用DISTINCT语句。有时我需要在多个列上进行区分,这在SQL语法中是完全正确的,但是我不知道如何在jOOQ中做到这一点。

我使用CASE进行计数,因为我也有更多条件的查询。为了方便起见,我简化了这些示例。

有效的SQL示例:

select
   count(distinct (case when "UserID" = 11 then "CategoryID" end)) as "UserCatNum",
   count(distinct (case when "UserID" = 11 then ("CategoryID", "PageID") end)) as "UserPageNum"
from data_table

当我只尝试一个字段时,它会起作用:

query.addSelect(
    DSL.countDistinct(
        DSL.when(DSL.condition(Operator.AND, conditions), CATEGORY_ID)
    ).as("UserCatNum")
);

但是当我尝试这样的事情时:

query.addSelect(
    DSL.countDistinct(
        DSL.when(DSL.condition(Operator.AND, conditions),
        DSL.row(CATEGORY_ID, PAGE_ID))
    ).as("UserPageNum")
);

我遇到以下错误:

Cannot interpret argument of type class org.jooq.impl.RowImpl as a Field: ("data_table"."CategoryID", "data_table"."PageID")

我尝试了DSL.row(),因为我发现IN语句也有类似用法。我还尝试用DSL.select()替换它,但它既无效,数组和列表均无效。

现在我通过编写一个小函数解决了这个问题:

private Field<Object> tupleField(Field... fields) {
    String tuple = Arrays.stream(fields)
        .map(f -> f.getQualifiedName().quotedName().toString())
        .collect(Collectors.joining(","));

    return DSL.field("(" + tuple + ")");
}

但是很高兴知道如何使用jOOQ的API做到这一点。

2 个答案:

答案 0 :(得分:1)

可以使用实验性的org.jooq.Row2方法将行值表达式(例如org.jooq.Field)转换为普通列表达式(DSL.rowField())。

然后这将在API中起作用,并且可能会生成适当的预期SQL,但从jOOQ 3.11 / 3.12开始,此支持仍处于试验阶段,尚未得到很好的测试。行字段很可能在CASE表达式之类的表达式中使用时,不会从数据库中正确获取。

答案 1 :(得分:0)

SQL起作用的原因是因为("CategoryID", "PageID")被解释为 tuple ,而Postgres可以对它们进行计数。否则,count(distinct)不会采用多个表达式。

我不知道如何在JOOQ中创建元组。但是,您可能可以执行一些字符串连接以生成"CategoryID" || ':' || "PageID"并获得所需的结果。