【问题标题】:Summarizing/aggregating a Scala Slick object into another将 Scala Slick 对象汇总/聚合到另一个对象中
【发布时间】:2013-11-20 04:53:50
【问题描述】:

我实际上是在尝试使用 Scala Slick 重新创建以下 SQL 查询:

select labelOne, labelTwo, sum(countA), sum(countB) from things where date > 'blah' group by labelOne, labelTwo;

如您所见,它需要一张带有标签的表格,然后将它们聚合起来,汇总各种计数。包含以下信息的表格:

ID | date | labelOne | labelTwo | countA | countB
-------------------------------------------------
0  | 0    | foo      | cheese   | 1      | 2
1  | 0    | bar      | wine     | 0      | 3
2  | 1    | foo      | cheese   | 3      | 4
3  | 1    | bar      | wine     | 2      | 1
4  | 2    | foo      | beer     | 1      | 1

如果查询所有日期,应产生以下结果:

labelOne | labelTwo | countA | countB
-------------------------------------
foo      | cheese   | 4      | 6
bar      | wine     | 2      | 4
foo      | beer     | 1      | 1

这就是我的 Scala 代码的样子:

import scala.slick.driver.MySQLDriver.simple._
import scala.slick.jdbc.StaticQuery
import StaticQuery.interpolation
import org.joda.time.LocalDate
import com.github.tototoshi.slick.JodaSupport._

case class Thing(
  id: Option[Long],
  date: LocalDate,
  labelOne: String,
  labelTwo: String,
  countA: Long,
  countB: Long)

// summarized version of "Thing": note there's no date in this object
// each distinct grouping of Thing.labelOne + Thing.labelTwo should become a "SummarizedThing", with summed counts
case class SummarizedThing(
  labelOne: String,
  labelTwo: String,
  countASum: Long,
  countBSum: Long)

trait ThingsComponent {
  val Things: Things

  class Things extends Table[Thing]("things") {
    def id       = column[Long]("id", O.PrimaryKey, O.AutoInc)
    def date     = column[LocalDate]("date", O.NotNull)
    def labelOne = column[String]("labelOne", O.NotNull)
    def labelTwo = column[String]("labelTwo", O.NotNull)
    def countA   = column[Long]("countA", O.NotNull)
    def countB   = column[Long]("countB", O.NotNull)

    def * = id.? ~ date ~ labelOne ~ labelTwo ~ countA ~ countB <> (Thing.apply _, Thing.unapply _)

    val byId = createFinderBy(_.id)
  }
}

object Things extends DAO {
  def insert(thing: Thing)(implicit s: Session) { Things.insert(thing) }

  def findById(id: Long)(implicit s: Session): Option[Thing] = Things.byId(id).firstOption

  // ???
  def summarizeSince(date: LocalDate)(implicit s: Session): Set[SummarizedThing] = {
    Query(Things).where(_.date > date).groupBy(x => (x.labelOne, x.labelTwo)).map {
      case(thing: Thing) => {
        // obviously this line below is wrong, but you can get an idea of what I'm trying to accomplish:
        // create a new SummarizedThing for each unique labelOne + labelTwo combo, summing the count columns
        new SummarizedThing(thing.labelOne, thing.labelTwo, thing.countA.sum, thing.countB.sum)
      }
    } // presumably need to run the query and map to SummarizedThing here, perhaps?
  }
}

summarizeSince 函数是我遇到问题的地方。我似乎能够很好地查询Things,按日期过滤并按我的字段分组......但是,我遇到了麻烦求和 countAcountB。有了总和结果,我想为每个独特的 labelOne + labelTwo 组合创建一个 SummarizedThing。希望这是有道理的。任何帮助将不胜感激。

【问题讨论】:

    标签: mysql scala playframework playframework-2.0 slick


    【解决方案1】:

    大概需要在这里运行查询并映射到 SummarizedThing,也许?

    没错。

    Query(Things).filter(_.date > date).groupBy(x => (x.labelOne, x.labelTwo)).map {
      // match on (key,group) 
      case ((labelOne, labelTwo), things) => {
        // prepare results as tuple (note .sum returns an Option)
        (labelOne, labelTwo, things.map(_.countA).sum.get, things.map(_.countB).sum.get)
      }
    }.run.map(SummarizedThing.tupled) // run and map tuple into case class
    

    【讨论】:

    • 好的,我花了一点时间才弄清楚这里发生了什么:case ((labelOne, labelTwo), things)... 非常简洁,谢谢。
    【解决方案2】:

    与其他答案相同,但表示为理解,除了 .get 是例外,因此您可能需要 getOrElse

    val q = for { 
      ((l1,l2), ts) <- Things.where(_.date > date).groupBy(t => (t.labelOne, t.labelTwo)) 
    } yield (l1, l2, ts.map(_.countA).sum.getOrElse(0L), ts.map(_.countB).sum.getOrElse(0L))
    
    // see the SQL that generates.
    println( q.selectStatement )
    // select x2.`labelOne`, x2.`labelTwo`, sum(x2.`countA`), sum(x2.`countB`) 
    // from `things` x2 where x2.`date` > '2013' group by x2.`labelOne`, x2.`labelTwo`
    
    // map the result(s) of your query to your case class
    q.map(SummarizedThing.tupled).list
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-02
      • 2021-12-18
      • 2012-08-26
      • 1970-01-01
      • 1970-01-01
      • 2019-07-30
      • 1970-01-01
      • 2013-02-13
      相关资源
      最近更新 更多