sql >> データベース >  >> RDS >> Mysql

滑らかなダイナミックグループ

    Slick 3.2.3の回避策(および私のアプローチの背景)は次のとおりです。

    動的に選択していることに気づいたかもしれません 固定タイプを想定できる限り、列は簡単です。例: columnNames = List("col1", "col2") tableQuery.map( r => columnNames.map(name => r.column[String](name)) )

    ただし、同様のアプローチを試してください groupByを使用 操作すると、Slickは"does not know how to map the given types"と文句を言います。 。

    したがって、これは洗練されたソリューションとは言えませんが、両方を静的に定義することで、少なくともSlickの型安全性を満たすことができます。

    1. groupby 列タイプ
    2. groupByの数量の上限/下限 列

    これらの2つの制約を実装する簡単な方法は、再び固定型を想定し、groupByのすべての可能な量に対してコードを分岐することです。 列。

    これがあなたにアイデアを与えるための完全に機能するScalaREPLセッションです:

    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)
    

    これが醜くなるのは、いくつかのgroupBy以上を使用できる場合です。 列(つまり、個別のif 10以上の場合のブランチは単調になります)。うまくいけば、誰かが急いでこの答えを編集して、その定型文を構文糖衣または抽象化レイヤーの後ろに隠す方法を学びます。




    1. SQL Server(T-SQL)で列の照合を設定する方法

    2. 行に重複データが含まれている場合、行を強調表示するにはどうすればよいですか?

    3. SugarCRM-データベース障害-行サイズが大きすぎますか?

    4. MariaDBでのMOD()のしくみ