2013-07-22 48 views
8

例如,我有以下表定義:如何在Slick中進行彙總查詢?

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 size = column[Int]("size") 
    def * = id ~ houseId ~ size 
} 

我想選擇每個房子的最大的房間。

我想出了下面的技巧:

val query = { 
    (r1, r2) <- Rooms leftJoin Rooms on ((r1,r2) => 
    r1.houseId === r2.houseId && r1.size > r2.size 
) 
    if r2.id.isNull 
} yield r1 

它做什麼,我需要的,但很醜,完全不可讀的,而且似乎會降低性能。我試圖在查詢上使用groupBy,但似乎我誤解了一些核心概念 - 我無法獲得正確的類型。

有沒有更好的方法在Slick中做這樣的聚合查詢?

回答

8

首先,這種查詢在普通SQL中並不完全簡單。油滑GROUPBY轉換爲SQL GROUP BY到底,所以使用它,我們需要與A組SQL查詢BY

一個這樣的查詢可能看起來像

SELECT r2.* FROM 
    (SELECT r.houseId, MAX(size) as size FROM Rooms r GROUP BY r.houseId) mx 
    INNER JOIN 
    Rooms r2 on r2.size = mx.size and r2.houseId = mx.houseId 

這現在可以翻譯成光滑

val innerQuery = Query(Rooms).groupBy(_.houseId).map { 
    case (houseId, rows) => (houseId, rows.map(_.size).max) 
} 

val query = for { 
    (hid, max) <- innerQuery 
    r <- Rooms if r.houseId === hid && r.size === max 
} yield r 

但是,我在使用當前版本的slick中的其他查詢中使用的聚合查詢時遇到了問題。

但查詢可以不帶GROUP寫入使用EXISTS

SELECT r.* FROM Rooms r 
    WHERE NOT EXISTS (
    SELECT r2.id FROM Rooms r2 WHERE r2.size > r.size and r2.houseId = r.houseId) 

這可以再次被翻譯成光滑

val query = for { 
    r <- Rooms 
    if !Query(Rooms).filter(_.houseId === r.houseId).filter(_.size > r.size).exists 
} yield r 

另一種選擇很可能是使用的window functions,但我可以」這對你們來說真的很有幫助,我不認爲滑頭可以和他們一起工作。

(請注意,我沒有手頭有Scala編譯器所以有可能在代碼中的錯誤)

+0

謝謝!具有'存在'的版本確實快得多,並且行距減少了30倍。 – Rogach