如何在Grails GORM Projections中使用sum(case when...)语句?
在Grails GORM Projections中实现SUM(CASE WHEN...)统计
当然可以实现这种自定义聚合统计,但你当前代码里用sqlRestriction的方式是错的——这个方法是用来添加查询条件(比如WHERE/HAVING子句)的,不是用来定义SELECT中的投影字段的。正确的做法是使用sqlProjection方法来定义这个自定义聚合字段。
问题修正与实现步骤
替换错误的
sqlRestriction
把你代码里的sqlRestriction ("sum(case when status = 0 then 1 else 0 end) waiting_data")替换为sqlProjection,这个方法专门用来在projections中嵌入原生SQL片段:sqlProjection("sum(case when status = 0 then 1 else 0 end) as waiting_data", ["waiting_data"], [Long.class])参数说明:
- 第一个参数:原生SQL片段,必须给统计字段加别名(
as waiting_data) - 第二个参数:别名列表,和SQL片段里的别名对应
- 第三个参数:返回类型列表,这里统计数量用
Long.class最合适
- 第一个参数:原生SQL片段,必须给统计字段加别名(
清理重复的分组字段
你代码里重复写了groupProperty("proj.name"),这会导致分组逻辑冗余,需要删掉其中一个。
完整修正后的代码示例
return Product.createCriteria().list() { resultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP) // 记得添加关联对象的别名(如果Product和so/acc/proj是关联关系) createAlias("so", "so") createAlias("acc", "acc") createAlias("proj", "proj") projections { count("id") property("so.id", "id") property("so.soNumber", "soNumber") property("so.dateCreated", "dateCreated") property("acc.name", "account_name") property("proj.name", "project_name") property("gtin", "gtin") property("status", "status") property("statusDate", "status_date") // 自定义SUM(CASE WHEN...)统计 sqlProjection("sum(case when status = 0 then 1 else 0 end) as waiting_data", ["waiting_data"], [Long.class]) // 分组字段(确保所有非聚合的property字段都在这里) groupProperty("so.id") groupProperty("so.soNumber") groupProperty("so.dateCreated") groupProperty("acc.name") groupProperty("proj.name") groupProperty("gtin") groupProperty("status") groupProperty("statusDate") } }
额外提示
- 如果需要统计多个状态的数量,只需添加多个
sqlProjection即可,比如统计已处理的数量:sqlProjection("sum(case when status = 1 then 1 else 0 end) as processed_data", ["processed_data"], [Long.class]) - 确保所有在
property中声明的非聚合字段都出现在groupProperty里,否则数据库会抛出分组查询的语法错误(这是SQL的通用规则)
内容的提问来源于stack exchange,提问作者Mister B
相关产品推荐
相关产品推荐

