1

我实际上是在尝试使用 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. 有了总和的结果,我想SummarizedThing为每个独特的labelOne + labelTwo组合创建一个。希望这是有道理的。任何帮助将不胜感激。

4

2 回答 2

4

大概需要在这里运行查询并映射到 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
于 2013-11-08T09:32:09.420 回答
1

与其他答案相同,但表示为 for 理解,但这.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
于 2013-11-08T09:57:46.713 回答