5

サンプルデータベーステーブル:

  1. ID = 1、msgFrom ='こんにちは'、foobar ='meh'
  2. ID = 2、msgFrom ='さようなら'、foobar='コメント'
  3. ID = 3、msgFrom ='こんにちは'、foobar='応答'

必要な出力のサンプル(Hibernateクエリによって生成):

  1. ID = 1、msgFrom ='こんにちは'、foobar ='meh'
  2. ID = 2、msgFrom ='さようなら'、foobar='コメント'

上記の例では、msgFrom列が同じであるため、3番目のレコードは結果から除外されます。Java/HibernateクラスがMessageと呼ばれているとしましょう。結果をメッセージオブジェクト(またはとにかくメッセージにキャストできるオブジェクト)のリストとして返したいのですが。可能であればCriteriaAPIを使用したいと思います。この例をSOで見ましたが、似ているように見えますが、現時点では正しく実装できません。

 select e from Message e 
    where e.msgFrom IN (select distinct m.msgFrom 
                          from Message m
                          WHERE m.msgTo = ? 
                          AND m.msgCheck = 0");

これを行う理由は、データベースで個別のレコードのフィルタリングを実行するためです。そのため、アプリケーションサーバーで何かをフィルタリングする必要がある回答には興味がありません。

編集:基本的に私がやりたいことを示す記事。http://oscarvalles.wordpress.com/2008/01/28/sql-distinct-on-one-column-only/

4

3 に答える 3

6

これを試して、私に知らせてください

DetachedCriteria msgFromCriteria = DetachedCriteria.forClass(Message.class);
ProjectionList properties = Projections.projectionList();
properties.add(Projections.groupProperty("messageFrom"));
properties.add(Projections.min("id"),"id");
msgFromCriteria.setProjection(properties);

Criteria criteria = s.createCriteria(Message.class);
criteria.add(Subqueries.propertiesIn(new String[]{"messageFrom","id"}, 
    msgFromCriteria));
List<Message> list = criteria.list();

for(Message message:list){
    System.out.println(message.getId()
        +"-------"
        +message.getMessageFrom()
        +"-----"
        +message.getFoobar());
}
于 2012-08-23T18:21:26.743 に答える
2

このクエリの難しさは、Hibernate自体ではそれほど重要ではありませんが、一般的なリレーショナルモデルでは問題になります。この例では、1行目と2行目を期待していると言いますが、2行目と3行目を同じように簡単に期待しないのはなぜですか。行1と行3のどちらもmsgFromフィールドの値が同じであるため、どちらを返すかは任意の決定になります。データベースはこのような恣意的な決定を下しません。そのためdistinct、サブセットではなく、選択した列のリスト全体に適用する必要があります。最初に一致する行を取得するデータベース固有の方法があります。たとえば、見てください

1つの列でDISTINCTを選択

一致する行のどれを返すかを決定するために使用できる日付列がある場合もありますが、クエリはやや複雑になります。

SQLの別の列でMAX(列値)、DISTINCTの行を選択するにはどうすればよいですか?

列の最大値を持つ行をフェッチします

他の列を気にしない場合は、distinctHibernateのコンストラクター構文(テストされていない)と組み合わせた単純なものを使用できます。

select new Message(msgFrom) from (select distinct msgFrom from Message)

ただし、他のすべての列を破棄することを受け入れる必要があります。

結局、私はしばしばこれをポストクエリフィルターとしてコードで行うことになります。別のオプションは、キーの一部としてmsgFromを含む別のテーブル(CurrentMessageなど)を作成することです。このテーブルを最新の状態に保つにはさらに多くの作業が必要になりますが(メッセージテーブルに行を追加するたびに行を更新する必要があります)、クエリははるかに簡単になります。

于 2012-08-16T19:39:47.000 に答える
0
DetachedCriteria msgFromCriteria = DetachedCriteria.forClass(Message.class);
msgFromCriteria.setProjection(Projections.distinct(Projections.property("msgFrom")));
....
Criteria criteria = getSession().createCriteria(Message.class);
criteria.add(Subqueries.propertyIn("msgFrom", msgFromCriteria));
criteria.list();
于 2012-08-13T23:56:23.893 に答える