Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Grup dinamis yang apik oleh

Berikut adalah solusi untuk Slick 3.2.3 (dan beberapa latar belakang pendekatan saya):

Anda mungkin telah memperhatikan secara dinamis memilih kolom mudah selama Anda dapat mengasumsikan tipe tetap, misalnya: columnNames = List("col1", "col2") tableQuery.map( r => columnNames.map(name => r.column[String](name)) )

Namun jika Anda mencoba pendekatan serupa dengan groupBy operasi, Slick akan mengeluh bahwa "does not know how to map the given types" .

Jadi, meskipun ini bukanlah solusi yang elegan, Anda setidaknya dapat memenuhi keamanan tipe Slick dengan mendefinisikan keduanya secara statis:

  1. groupby jenis kolom
  2. Batas atas/bawah pada jumlah groupBy kolom

Cara sederhana untuk mengimplementasikan kedua batasan ini adalah dengan mengasumsikan kembali tipe tetap dan membuat cabang kode untuk semua jumlah groupBy yang mungkin. kolom.

Inilah sesi REPL Scala yang berfungsi untuk memberi Anda gambaran:

import java.io.File

import akka.actor.ActorSystem
import com.typesafe.config.ConfigFactory
import slick.jdbc.H2Profile.api._

import scala.concurrent.{Await, Future}
import scala.concurrent.duration._


val confPath = getClass.getResource("/application.conf")
val config = ConfigFactory.parseFile(new File(confPath.getPath)).resolve()
val db = Database.forConfig("slick.db", config)

implicit val system = ActorSystem("testSystem")
implicit val executionContext = system.dispatcher

case class AnyData(a: String, b: String)
case class GroupByFields(a: Option[String], b: Option[String])

class AnyTable(tag: Tag) extends Table[AnyData](tag, "macro"){
  def a = column[String]("a")
  def b = column[String]("b")
  def * = (a, b) <> ((AnyData.apply _).tupled, AnyData.unapply)
}

val table = TableQuery[AnyTable]

def groupByDynamically(groupBys: Seq[String]): DBIO[Seq[GroupByFields]] = {
  // ensures columns are returned in the right order
  def selectGroups(g: Map[String, Rep[Option[String]]]) = {
    (g.getOrElse("a", Rep.None[String]), g.getOrElse("b", Rep.None[String])).mapTo[GroupByFields]
  }

  val grouped = if (groupBys.lengthCompare(2) == 0) {
    table
      .groupBy( cols => (cols.column[String](groupBys(0)), cols.column[String](groupBys(1))) )
      .map{ case (groups, _) => selectGroups(Map(groupBys(0) -> Rep.Some(groups._1), groupBys(1) -> Rep.Some(groups._2))) }
  }
  else {
    // there should always be at least one group by specified
    table
      .groupBy(cols => cols.column[String](groupBys.head))
      .map{ case (groups, _) => selectGroups(Map(groupBys.head -> Rep.Some(groups))) }
  }

  grouped.result
}

val actions = for {
  _ <- table.schema.create
  _ <- table.map(a => (a.column[String]("a"), a.column[String]("b"))) += ("a1", "b1")
  _ <- table.map(a => (a.column[String]("a"), a.column[String]("b"))) += ("a2", "b2")
  _ <- table.map(a => (a.column[String]("a"), a.column[String]("b"))) += ("a2", "b3")
  queryResult <- groupByDynamically(Seq("b", "a"))
} yield queryResult

val result: Future[Seq[GroupByFields]] = db.run(actions.transactionally)
result.foreach(println)

Await.ready(result, Duration.Inf)

Di mana ini menjadi jelek adalah ketika Anda dapat memiliki lebih dari beberapa groupBy kolom (yaitu memiliki if separate yang terpisah cabang untuk 10+ kasus akan menjadi monoton). Semoga seseorang akan masuk dan mengedit jawaban ini untuk cara menyembunyikan boilerplate itu di balik beberapa gula sintaksis atau lapisan abstraksi.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Database kosong di MySQL dan PHP?

  2. mysql tidak dapat dimulai di Lingkungan Pengembangan Mgt

  3. Di mana saya dapat menemukan log transaksi MySQL?

  4. Offset batas negatif di mysql

  5. Flask-SQLAlchemy memeriksa apakah server database responsif