Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Slick động groupby

Đây là một giải pháp cho Slick 3.2.3 (và một số thông tin cơ bản về cách tiếp cận của tôi):

Bạn có thể nhận thấy động chọn cột dễ dàng miễn là bạn có thể giả sử một loại cố định, ví dụ: columnNames = List("col1", "col2") tableQuery.map( r => columnNames.map(name => r.column[String](name)) )

Nhưng nếu bạn hãy thử một cách tiếp cận tương tự với một groupBy hoạt động, Slick sẽ phàn nàn rằng nó "does not know how to map the given types" .

Vì vậy, mặc dù đây không phải là một giải pháp thanh lịch, nhưng ít nhất bạn có thể đáp ứng mức độ an toàn về kiểu chữ của Slick bằng cách xác định tĩnh cả hai:

  1. groupby loại cột
  2. Giới hạn trên / dưới về số lượng groupBy cột

Một cách đơn giản để thực hiện hai ràng buộc này là một lần nữa giả sử một kiểu cố định và phân nhánh mã cho tất cả các số lượng có thể có của groupBy cột.

Đây là phiên Scala REPL đầy đủ hoạt động để cung cấp cho bạn ý tưởng:

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)

Điều này trở nên tồi tệ đến đâu khi bạn có thể có một vài groupBy các cột (nghĩa là có một if riêng biệt nhánh cho 10 trường hợp trở lên sẽ trở nên đơn điệu). Hy vọng rằng ai đó sẽ tìm thấy và chỉnh sửa câu trả lời này để biết cách ẩn bảng soạn sẵn đó đằng sau một số đường cú pháp hoặc lớp trừu tượng.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Chọn hiệu quả bản ghi (khoảng cách) gần nhất từ ​​cơ sở dữ liệu

  2. C # - Ngoại lệ phương thức xác thực không mong đợi mysql_native_password

  3. MySQL:ALTER TABLE nếu cột không tồn tại

  4. Tạo truy vấn để có được số lượng nhóm cuộc gọi chưa hoàn thành theo 2 trường

  5. Tại sao XAMPP không phù hợp để sản xuất?