2013-07-22 2 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ので、我々は、GROUP BYとSQLクエリを必要とし、それを使用して、最後にSQL GROUP 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 BYせずに書き込むことができます。これは、再び別のオプションは、おそらくwindow functionsの使用だろうが、私は」することができます滑らかな

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

に変換することができ

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

をEXISTS本当にそれらを手伝ってくれるので、スリックは彼らと一緒に働くことはできません。

(現時点ではスカラーコンパイラがないため、コードにエラーがある可能性があります)

+0

ありがとうございます!バージョンが 'exists'のほうがはるかに高速で、行が30倍少なくなります。 – Rogach

関連する問題