2013-07-03 41 views
2

當我試圖對查詢執行Query(query.length).first時,表示包含多個具有相同名稱的列的2個表的連接,我得到的格式不正確的sql。請看例子:如何統計Slick中連接返回的行數?

// 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的拒絕,因爲id列在select x4.id, x5.id部分重複。

我可以嘗試做如下:

query.list.size 

但會從查詢提取的所有行,並將它們發送線,這將會極大地阻礙性能。

我在做什麼錯?有沒有辦法解決它?

回答

6

這是一個有趣的問題。通常使用SQL,你別名可能會導致名稱衝突的列,但我不確定Slick如何工作(或者甚至可能)。但你可以解決這一點,我相信通過僅選擇一列,如果你只是想算:

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

現在count呼叫id已過時,但是這一次產生了乾淨的SQL語句看起來像這樣:我使用.length試圖

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

任何產生了一堆的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列。在這種情況下,因爲結果是Tuple2,我必須進一步去id列,但我認爲你會得到這張照片。

+0

確實有效。我希望有一個通用的'Query [A,B]'案例的解決方案,因爲這樣可以減少代碼中的殘留(當前的解決方案需要我爲每個查詢手寫計數代碼)。但是由於我不知道如何才能實現一般的解決方案,這是唯一的方法。 – Rogach

+0

@Rogach,我在答覆中添加了更多詳細信息以迴應您的評論。 – cmbaxter

+0

謝謝!但我的意思是另一回事。例如,我有一個輔助方法'runApiQuery [A,B](query:Query [A,B])',它從查詢中獲取內容,應用限制,計算查詢對象等。如果Query上的'.length'工作正常,我可以在方法內部執行'query.length',而不會增加'runApiQuery'調用者的負擔(因爲Slick團隊已經6天沒有評論這個bug了,可能不會很快發生)。在當前情況下,我只能向runApiQuery添加一個參數:'runApiQuery [A,B,C](q:Query [A,B])(countCol:A => Column [C])'並且稍後使用countCol身體。 – Rogach