3

当我尝试执行Query(query.length).first一个查询时,它表示 2 个表的连接,这些表具有多个具有相同名称的列,我得到了格式错误的 sql。考虑这个例子:

// in Main.scala
import scala.slick.driver.MySQLDriver.simple._
object Main extends App {

  object Houses extends Table[Long]("Houses") {
    def id = column[Long]("id")
    def * = id
  }
  object Rooms extends Table[(Long, Long)]("Rooms") {
    def id = column[Long]("id")
    def houseId = column[Long]("houseId")
    def * = id ~ houseId
  }

  val query = for {
    h <- Houses
    r <- Rooms
    if h.id === r.houseId
  } yield (h, r)
  println("QUERY: " + Query(query.length).selectStatement)
}

// in build.sbt
scalaVersion := "2.10.2"

libraryDependencies += "com.typesafe.slick" %% "slick" % "1.0.1"

此示例生成以下 SQL:

select x2.x3 from
  (select count(1) as x3 from 
    (select x4.`id`, x5.`id`, x5.`houseId` 
     from `Houses` x4, `Rooms` x5 where x4.`id` = x5.`houseId`) x6) x2

这显然是错误的,并且被 MySQL 拒绝,因为idselect x4.id, x5.id部分重复。

我可以尝试执行以下操作:

query.list.size

但这会从查询中提取所有行并通过网络发送它们,这将极大地影响性能。

我究竟做错了什么?有什么办法可以解决吗?

4

1 回答 1

6

这是一个有趣的问题。通常使用 SQL,您会为另一列起别名,这会导致名称冲突,但我不确定它如何与 Slick 一起使用(或者甚至可能)。但是,如果您只想计数,我相信您可以通过仅选择一列来解决此问题:

val query = for {
  h <- Houses
  r <- Rooms
  if h.id === r.houseId
} yield h.id.count

现在不推荐使用counton 调用id,但是这个调用生成了一个干净的 sql 语句,如下所示:

select count(x2.`id`) from `Houses` x2, `Rooms` x3 where x2.`id` = x3.`houseId`

我尝试使用的任何东西都会.length产生一堆不正确的 sql。

编辑

作为对您的评论的回应,您希望将查询保持原样(让我们忘记查询本身由于连接中的字段冲突/歧义而被破坏),然后还能够从中派生一个计数查询,看起来像这样:

def main(args: Array[String]) {
  val query = for {
    h <- Houses
    r <- Rooms
    if h.id === r.houseId
  } yield (h,r)

  val lengthQuery = query.map(_._1.id.count)
}

这里的要点是,您应该能够map通过选择单个列(而不是完整对象)然后count为该列获取任何查询并将其用于计数查询。在这种情况下,因为结果是 a Tuple2,所以我必须进入一个额外的级别才能到达该id列,但我想你明白了。

于 2013-07-12T00:52:32.653 回答