根据ScalaQuery/SLICK中列的MAX值选择行

Ang*_*nco 11 scala subquery max scalaquery slick

说我有这样的表:

UserActions
    UserId INT
    ActionDate TIMESTAMP
    Description TEXT
Run Code Online (Sandbox Code Playgroud)

包含用户执行某些行为的日期.如果我想获得每个用户执行的最后一个操作,我将不得不在SQL中执行以下操作:

SELECT *
FROM   UserActions,
       (
           SELECT ua.UserId,
                  max(ua.ActionDate) AS lastActionDate
           FROM   UserActions ua
           GROUP BY ua.UserId
       ) AS lastActionDateWithUserId
WHERE  UserActions.UserId = lastActionDateWithUserId.UserId 
  AND  UserActions.ActionDate = lastActionDateWithUserId.lastActionDate
Run Code Online (Sandbox Code Playgroud)

现在,假设我已经在scalaquery 0.9.5中为UserActions设置了表结构,例如:

case class UserAction(userId:Int,actionDate:Timestamp,description:String)

object UserActions extends BasicTable[UserAction]("UserActions"){

    def userId = column[Int]("UserId")

    def actionDate = column[Timestamp]("ActionDate")

    def description  = column[String]("Description")

    def * = userId ~ actionDate ~ description <> (UserAction, UserAction.unapply _)
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:在ScalaQuery/SLICK中我该如何执行这样的查询?

EEC*_*LOR 10

我使用Slick 1.0.0和Scala 2.10.

我定义了这样的对象:

case class UserAction(userId: Int, actionDate: Timestamp, description: String)

object UserActions extends Table[UserAction]("UserActions") {

  def userId = column[Int]("UserId")
  def actionDate = column[Timestamp]("ActionDate")
  def description = column[String]("Description")
  def * = userId ~ actionDate ~ description <> (UserAction, UserAction.unapply _)
}
Run Code Online (Sandbox Code Playgroud)

在会话块内

Database.forURL("jdbc:h2:mem:test1", driver = "org.h2.Driver") withSession {
  //...
}
Run Code Online (Sandbox Code Playgroud)

我插入了一些样本数据

UserActions.insert(UserAction(10, timeStamp, "Action 1"))
UserActions.insert(UserAction(10, timeStamp, "Action 2"))
UserActions.insert(UserAction(10, timeStamp, "Action 3"))
UserActions.insert(UserAction(20, timeStamp, "Action 1"))
UserActions.insert(UserAction(20, timeStamp, "Action 2"))
UserActions.insert(UserAction(30, timeStamp, "Action 1"))

Query(UserActions).list foreach println
Run Code Online (Sandbox Code Playgroud)

首先要做的是创建最大查询

// group by userId and select the userId and the max of the actionDate
val maxQuery =
  UserActions
    .groupBy { _.userId }
    .map {
      case (userId, ua) =>
        userId -> ua.map(_.actionDate).max
    }
Run Code Online (Sandbox Code Playgroud)

生成的查询如下所示

val result =
  for {
    ua <- UserActions
    m <- maxQuery
    if (ua.userId === m._1 && ua.actionDate === m._2)
  } yield ua

result.list foreach println
Run Code Online (Sandbox Code Playgroud)