scala - 如何在 Slick 中进行聚合查询?

标签 scala scala-2.10 slick

例如,我有以下表定义:

object Houses extends Table[Long]("Houses") {
  def id = column[Long]("id")
  def * = id
}
object Rooms extends Table[(Long, Long)]("Rooms") {
  def id = column[Long]("id")
  def houseId = column[Long]("houseId")
  def size = column[Int]("size")
  def * = id ~ houseId ~ size
}

我想为每个房子选择最大的房间。

我想出了以下技巧:
val query = {
  (r1, r2) <- Rooms leftJoin Rooms on ((r1,r2) =>
    r1.houseId === r2.houseId && r1.size > r2.size
  )
  if r2.id.isNull
} yield r1

它可以满足我的需求,但很丑陋,完全无法阅读,并且似乎会损害性能。我尝试使用 groupBy关于查询,但似乎我误解了一些核心概念 - 我无法正确获取类型。

有没有更好的方法在 Slick 中进行这样的聚合查询?

最佳答案

首先,这种查询在普通 SQL 中并不完全简单。 Slick groupBy 最终会转换为 SQL GROUP BY,因此要使用它,我们需要一个带有 GROUP BY 的 SQL 查询

一个这样的查询可能看起来像

SELECT r2.* FROM 
  (SELECT r.houseId, MAX(size) as size FROM Rooms r GROUP BY r.houseId) mx
  INNER JOIN
  Rooms r2 on r2.size = mx.size and r2.houseId = mx.houseId

这现在可以翻译成光滑的
val innerQuery = Query(Rooms).groupBy(_.houseId).map {
  case (houseId, rows) => (houseId, rows.map(_.size).max)
}

val query = for {
  (hid, max) <- innerQuery
  r <- Rooms if r.houseId === hid && r.size === max
} yield r

但是,我在当前版本的 slick 中的其他查询中使用了聚合查询时遇到了问题。

但是可以使用 EXISTS 在没有 GROUP BY 的情况下编写查询
SELECT r.* FROM Rooms r 
  WHERE NOT EXISTS (
    SELECT r2.id FROM Rooms r2 WHERE r2.size > r.size and r2.houseId = r.houseId)

这可以再次翻译为光滑
val query = for {
  r <- Rooms
  if !Query(Rooms).filter(_.houseId === r.houseId).filter(_.size > r.size).exists
} yield r

另一种选择可能是使用 window functions ,但我真的无法帮助您解决这些问题,而且我认为 slick 无法与它们一起工作。

(请注意,我手头没有 Scala 编译器,因此代码中可能存在错误)

关于scala - 如何在 Slick 中进行聚合查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17783886/

相关文章:

java - 尝试解密 RSA 时出错

mysql - 在光滑的操作中使用 scala 集合等价物是否有害?

json - Scala PlayJson 循环引用

scala - Scala 2.10 中的 Option.fold

sql - Slick 中的纯 SQL - 如何将 postgres 数组列映射到列表?

scala - sbt 插件动态加载用户定义的代码?

scala - 在 Scala 中定义具有多个隐式参数的函数

scala - 如何在 scala 宏内部从带有类型参数的类型获取类型参数?

Scala Play 2.2 应用程序在 Heroku 中部署后崩溃 : target/start No such file or directory

scala - Play scala 集成规范 - 通过 Guice 注入(inject)依赖项