Выберите строки на основе MAX значений столбца в ScalaQuery/SLICK

Скажем, у меня есть таблица, например:

UserActions
    UserId INT
    ActionDate TIMESTAMP
    Description TEXT

который содержит даты, когда пользователи выполняли определенные действия. Если бы я хотел получить последнее действие, которое выполнил каждый пользователь, мне пришлось бы сделать что-то вроде этого в 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

Теперь предположим, что у меня уже есть структура таблицы, настроенная в scalaquery 0.9.5 для действий пользователя, таких как:

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 _)
}

Мой вопрос: в ScalaQuery/SLICK, как я могу выполнить такой запрос?


person Angel Blanco    schedule 09.09.2012    source источник


Ответы (1)


Я использовал 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 _)
}

Внутри сеансового блока

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

Я вставил некоторые образцы данных

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

Первое, что нужно сделать, это создать максимальный запрос

// 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
    }

Результирующий запрос выглядит так

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

result.list foreach println
person EECOLOR    schedule 23.02.2013