【问题标题】:Random row in Scala Slick 3.0Scala Slick 3.0 中的随机行
【发布时间】:2026-02-15 07:00:01
【问题描述】:

如何有效地从表中取出一个随机行?

到目前为止我所拥有的(没有编译并且可能完全被误导了):

val query = for {
  m <- tableQuery
  maxId <- tableQuery.groupBy(_.id).map { case (tId, t) => t.map(_.id).max}//m.map(_.id).max
  if (m.id >= maxId * Random.nextFloat())
} yield m

编辑:经过一些修改并在 bhavya 的帮助下,我想出了以下代码,它可以完成这项工作,但会进行两次数据库往返:

val maxIdQuery: Rep[Option[Int]] = magicCardDumps.map(_.id).max
val maxIdFuture: Future[Option[Int]] = db.run(maxIdQuery.result)
val maxId = Await.result(maxIdFuture, 10 seconds).get
val randCardQuery: Query[MagicCardDumps, MagicCardDump, Seq] = magicCardDumps.filter(_.id >= (maxId * Random.nextFloat()).toInt).sortBy(_.id).take(1)
val resultFuture: Future[Seq[MagicCardDump]] = db.run(randCardQuery.result)
val resultSeq: Seq[MagicCardDump]= Await.result(resultFuture, Duration(10, "seconds"))
val card = resultSeq.head
println(card)

如何将这些查询合并为一个并提高效率?

【问题讨论】:

    标签: scala slick


    【解决方案1】:

    最好的方法是使用SimpleFuction

    val rand = SimpleFunction.nullary[Double]("rand")
    query.sortBy(x => rand).take(1)
    

    在 Postgres 和 MySQL 中工作

    【讨论】:

      【解决方案2】:

      希望这会有所帮助:

      val rowElementAsOpt = for {
        maxId <- Query(tableQuery.map(_.id).max).first
        result <- tableQuery.filter(_.id >= maxId*Random.nextFloat).firstOption // fetches the first element of the resultset as an Option 
      } yield result
      
      rowElementAsOpt match{
      case Some(rowElement) => // A random row  
      case None => // No row 
      

      【讨论】:

      • 函数 first 和 firstOption 不存在,如果我用 take(1) 替换它们,我得到一个乘法错误:Cannot perform option-mapped operation with type: (Option[Int], Float) =&gt; R for base type: (Int, Int) =&gt; Int
      • 这段代码针对 slick 2.10 而不是 3.0 进行了测试。可能是3.0版本有一些不同的语法。