2011-07-27 3 views
0

内側のクエリを排除:あなたが見ることができるようにのGrails/GORM/HQL:私はこの1つのような表「表」を持っている部分から

id  user_id  owner_id  due_date 
------+------------+-------------+-------------------------- 
1  | 1   | 1   | 2011-07-26 12:28:50 
2  | 1   | 1   | 2011-07-26 15:32:11 
3  | 1   | 1   | 2011-07-27 08:11:58 
4  | 2   | 1   | 2011-07-26 15:19:44 
5  | 2   | 1   | 2011-07-23 12:00:50 

を、FK user_idで識別されるユーザが持つ複数のエントリを持つことができます異なるdue_date

user_idでグループ化された最新のTableエンティティをすべてフェッチしたいと思います。無地のMySQLでは

、それは次のようになります。

SELECT * FROM (
    SELECT * FROM TABLE 
     WHERE owner_id = xxx 
     ORDER BY due_date DESC 
) AS sorted 
GROUP BY user_id 

を私が最初のORDER BYで選択することになり、その後、ここでGROUP BY(1 SELECT内のすべてのは、残念ながら、動作しません参照例えばhttp://www.cafewebmaster.com/mysql-order-sort-groupを適用します。 )。

これを(Grailsを使用して)HQLとして実装したいと思います。問題は、以下のアプローチが動作しませんので、HQLは、部分から内側のSELECTのをサポートしていないということです。

def findMostRecentPerUser(Owner owner) { 
    def result = Table.executeQuery(""" 
       from Table as t1 
       where t1.id in (
        select sorted.id from (select * from Table as t2 where t2.owner_id = ${owner.id} order by t2.due_date desc) as sorted group by sorted.user_id 
      ) 
     """) 
    return result 
} 

もう一つの方法は、基準だろうが、私はそのように実装するかさっぱりだが。

誰かが私に正しい方向を教えてくれますか?あなたの助けが大変ありがとうございます。

+0

日付のコレクションを返信しますか? –

+0

私は混乱していると思う。なぜサブクエリが必要ですか?それは日付で注文するだけですか? –

+0

Grails内でさらに使用するために、行全体、つまり完全な 'Table'エンティティを選択したいと考えています。私は元の質問でこれを明らかにしました。単純な 'GROUP BY user_id ORDER BY due_date'が正しい結果につながっていないので、サブクエリが必要です。同様の問題の説明についてはこちらをご覧ください:http://www.cafewebmaster.com/mysql-order-sort-group – void

答えて

0

この方法でうまくいくはずです。改善が評価されました。

def findMostRecentPerUser(Owner owner) { 
    // Inner query sorts maximum due_date per user 
    // Outer query fetches all Table entries with this due_date 
    def result = Table.executeQuery(""" 
      from Table as t1 
      where t1.due_date in (
       select max(t2.due_date) from Table as t2 where t2.owner = :owner group by t2.user 
      ) 
     """, 
     [ owner: owner ]) 
    return result 
} 
+0

正常に動作しているように見える、ありがとう! – void

0

MySqlをそのまま残し、結果を戻してComparatorを使用して並べ替えるのはなぜでしょうか。この方法で、データベースの実装方法に関係なく、ソートは同じになります。

List<Table> results = query(); 
Collections.sort(results, YourCustomComparator.getInstance()); 

これを実行すると、データベースの負荷が軽減されます。これは、次のような単純なクエリになります。

コレクションhereを参照してください。

+0

ありがとうあなたの返事のために、マイケル。結果セットがかなり大きくなり、ソートするためにすべてのレコードをロードしたくないので、これをクエリで処理することをお勧めします。また、HQLクエリは、データベース実装の詳細を抽象化する必要があります。 – void

0

あなたが意図していることが可能であるかどうかはわかりません。は生のSQLでする必要がありますか?

Group Byステートメントは、集計関数と組み合わせて使用​​すると意味がありますが、集計関数は使用していません。私はあなたの目標がこのようなデータ構造を得ることであると仮定します:[user_id_1: [t1, t5, t2], user_id_2: [t3, t4, t8]...](ここでtXはTableのインスタンスです)は正しいですか?

そのような場合、私はあなたがちょうどあなたが戻って気にインスタンスのセットを取得し、それらを自分で整理する必要があると思う:

def findMostRecentPerUser(Owner owner) { 
    def someDate = new Date() - 5 // 5 Days ago 
    def result = [:].withDefault{[]} 
    Table.withCriteria { 
    eq('owner.id', owner.id) 
    gt('due_date', someDate) 
    order('due_date', 'desc') 
    }.each{result[it.user.id] << it} 
    return result 
} 

しかし、あなたが見ることができるように、これが唯一のあなたの後に発生したインスタンスを提供します(または、gtステートメントを削除すると、すべてのインスタンスが提供されますが、これはおそらく必要ではありません)。 distinct('user.id')

しかし、各ユーザーの5つの最新のインスタンスが必要な場合は、ユーザーごとにクエリを実行していると思います結果セットを5に制限します)。私は誰かがこの事件の解決策を見ていることに非常に興味があります。

+0

あなたが仮定していることは正しいですが、ユーザーあたりの最新の行が1つだけであることを除いては正しいです。私はすでに別名を適用しようとしましたが、これは基本的に上記のGROUP BYの問題として問題を抱えています - 次のコードは、別個のものが最初に適用されるように見えるので間違った行を返します。 DEF結果= Table.withCriteria { \t EQ( "所有者"、所有者) \t突起{ \t \t異なる( "ユーザ") \t} \t順序( "DUE_DATE"、 "DESC") } – void

+0

あ、それはそうです。ええと...私が考えることができる唯一の他のものは、リファクタリングを伴います:ユーザーにmostRecentTableのフィールドを追加すると、そのプロパティに結合して正しい方法で結果を制限できます(Userオブジェクトを更新する必要があります関連するテーブルオブジェクトが作成されたときはいつでも - あなたがもっと良いかもしれない別の関連テーブルでそれを行うことができると仮定します)。私はあなたの質問に厳密に従うことについて他のアイデアは持っていません。がんばろう! – Kyle

関連する問題