如何在Slick中实现带Group By的多条件聚合求和?
在Slick中实现多聚合项的SQL查询
我来帮你把完整的SQL查询转换成Slick代码,咱们一步步拆解每个聚合逻辑,把你已经写好的单个求和扩展成完整的查询。
完整的Slick实现代码
假设你已经定义了taskEventStatuses表映射,以及Service枚举的Slick字符串映射(比如用MappedColumnType.base处理枚举与数据库字符串的转换),完整的实现如下:
import slick.jdbc.MySQLProfile.api._ // 根据你的数据库替换对应Profile import slick.lifted.{Case, If} // 提前定义Service枚举的Slick映射(示例) // implicit val serviceColumnType = MappedColumnType.base[Service, String](_.toString, Service.valueOf) val fullQuery = taskEventStatuses .groupBy(tes => tes.taskId) .map { case (taskId, group) => ( taskId, // 对应SQL中的WRITER_SUCCESSES(TOTAL_WRITER_SUCCESS) group.map(_.totalWriterSuccess).max, // 分组后取同taskId下的唯一值,用max/min/head均可 // 对应SQL中的WRITER_ERRORS(TOTAL_WRITER_ERRORS) group.map(_.totalWriterErrors).max, // 对应SQL中的READER_ERRORS求和逻辑 group.map(tes => If((tes.service === Service.Reader) && tes.error.isDefined, 1, 0)).sum, // 对应SQL中的READER_SUCCESSES求和逻辑 group.map(tes => If((tes.service === Service.Reader) && tes.error.isEmpty, 1, 0)).sum, // 对应SQL中的WRITER_CURRENT_ERRORS求和逻辑 group.map(tes => If( (tes.service === Service.Writer) && tes.error.isDefined && tes.totalWriterSuccess.isEmpty && tes.totalWriterErrors.isEmpty, 1, 0 )).sum ) }
关键细节说明
- 分组后的非聚合字段处理:原SQL中直接SELECT的
TOTAL_WRITER_SUCCESS和TOTAL_WRITER_ERRORS,因为GROUP BY TASK_ID后同组内这些值应该一致,所以在Slick中用max(或min/head)包裹,满足Slick对分组查询的语法要求。 - 条件判断转换:SQL里的
IF(condition,1,0)对应Slick的If(condition, 1, 0),Slick会自动把字面量转换为数据库兼容的类型。 - 空值判断:SQL中的
ERROR IS NOT NULL对应Slick的tes.error.isDefined,ERROR IS NULL对应tes.error.isEmpty,空字段的判断同理。 - 枚举匹配:确保
Service枚举的Slick映射已正确定义,这样tes.service === Service.Reader才能正确生成SERVICE = 'Reader'的SQL语句。
执行查询示例
你可以像执行普通Slick查询一样运行这段代码,比如:
// 假设db是你的Database实例 val queryResult: Future[Seq[(Long, Option[Int], Option[Int], Int, Int, Int)]] = db.run(fullQuery.result)
(类型参数请根据你的表字段实际类型调整,比如taskId类型、数值字段的可空性等)
内容的提问来源于stack exchange,提问作者shmuel buchnik
相关产品推荐
相关产品推荐

