web-dev-qa-db-ja.com

最大値を持つエンティティのHQLクエリ

次のようなHibernateエンティティがあります(簡潔にするためにアクセサーは省略されています)。

@Entity
@Table(name="FeatureList_Version")
@SecondaryTable(name="FeatureList",
    pkJoinColumns=@PrimaryKeyJoinColumn(name="FeatureList_Key"))
public class FeatureList implements Serializable {

    @Id
    @Column(name="FeatureList_Version_Key")
    private String key;

    @Column(name="Name",table="FeatureList")
    private String name;

    @Column(name="VERSION")
    private Integer version;

}

FeatureListの最新バージョンを取得するHQLクエリを作成します。次のクエリの並べ替えは機能します。

Select f.name, max(f.version) from FeatureList f group by f.name

問題は、キーフィールドが設定されないことです。キーフィールドには、指定されたFeatureListの最大バージョン番号を持つレコードのキーを含める必要があります。 selectにf.keyを追加すると、group byまたは集計にないため機能しません。また、f.keyをgroup byに入れるとすべてが機能しなくなり、すべてのバージョンが個別のエンティティとして提供されます。

だから、誰でも助けることができますか?

30
rjsang

このクエリの簡単なバージョンは次のようになります((name, version)ペアは一意です):

select f from FeatureList f 
where f.version = 
     (select max(ff.version) from FeatureList ff where ff.name = f.name)
58
axtavt

ここでシナリオを作成しました


テーブル

_key          name                 version         
----------- -------------------- ----------- 
1           adeel                1           
2           adeel                2           
3           adeel                3           
4           ahmad                1           
5           ahmad                2           
6           ahmad                3           
7           ahmad                4           
8           ansari               1           
9           ansari               2           
10          ansari               3           
_

元のクエリを使用した結果

_>> select f.name, max(f.version) from FeatureList f group by f.name

name                 max(f.version) 
-------------------- ------------ 
adeel                3            
ahmad                4            
ansari               3            
_

希望するクエリを使用した結果

_>> select fl.* from FeatureList fl 
   where (fl.name, fl.version) in (select f.name, max(f.version) 
                                           from FeatureList f group by f.name);

key          name                 max(fl.version)  
----------- -------------------- ----------- 
3           adeel                3           
7           ahmad                4           
10          ansari               3           
_

NB:今回はMySQLを使用して試してみました。その働き。 MS SQL ServerにはIN (...)演算子もあると確信しています。 Hibernateでsession.createNativeQuery()を使用するだけです。


axtavtの答え

わかったように、これは次のように簡単にできます。

_select f from FeatureList f 
where f.version = 
     (select max(ff.version) from FeatureList ff where ff.name = f.name)
_

Hibernate Criteria API を使用して同じことを試してください。

_DetachedCriteria versions = DetachedCriteria.forClass(FeatureList.class, "f")
    .setProjection( Property.forName("f.version").max())
    .add(Property.forName("f.name").eqProperty("fl.name"));

session.createCriteria(FeatureList.class, "fl")
    .add( Property.forName("fl.version").eq(versions) )
    .list();
_
13
Adeel Ansari

古い質問ですが、私はここで自分の経験を将来のユーザーにも提供すると思いました:

select f from FeatureList f where f.version = 
 (select max(ff.version) from FeatureList ff where ff.name = f.name);

これはうまく機能しますが、以下が当てはまる場合:

  • InnoDBエンジンを搭載したMySql v5.5
  • 必要な結果行の数は正確にわかっています(OCは1行のみが必要であることを意味しますが、上記のクエリはさまざまな数の結果に対して機能します)

以下は非常に高速です。

FROM FeatureList ORDER BY version DESC LIMIT 1;

テーブルに700,000個のレコードがある同様のクエリでの試行では、前のバージョンで約0.19秒、後者で約0.05秒かかります。

8
Mark McKenna

これはどう、

_from FeatureList fl where (fl.name, fl.version) in (
               select f.name, max(f.version) from FeatureList f group by f.name)
_

注:有効なOracleクエリであるcreateNativeQuery()で試してください。他のデータベースについては不明です。


1つの質問は、nameversionのペアは一意ですか?はいの場合は問題ありませんが、そうでない場合はペアが一意でない場合、キーがどのように選択されると思いますか?元のクエリのレコードの1つが、

_f.name         max(f.version)
------         --------------
Django         1.2
_

そして、同じペアを持つ3つのkeysがあると仮定します。では、このレコードにどのキーを割り当てる必要がありますか?あなたが私のポイントを得ていることを願っています。

3
Adeel Ansari

Group byの代わりにdistinct + order byを使用してはどうですか?

select f.id, distinct(f.name), f.version from FeatureList f order by f.version desc
0
Matt Brock