我将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做到这一点。
答案 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"
并获得所需的结果。