HQLでDistinctクエリを作成する方法


99

HQLでDistinctクエリを作成する方法はありますか?"distinct"キーワードまたはその他の方法を使用します。distinctがHQLの有効なキーワークであるかどうかはわかりませんが、SQLキーワード「distinct」に相当するHQLを探しています。

回答:


124

以下は、使用するhqlのスニペットです。(IDを保護するために名前が変更されました)

String queryString = "select distinct f from Foo f inner join foo.bars as b" +
                " where f.creationDate >= ? and f.creationDate < ? and b.bar = ?";
        return getHibernateTemplate().find(queryString, new Object[] {startDate, endDate, bar});

私はこれまでMySQLでhibernateのみを使用していました-mssqlの問題の対処方法がわかりません。
フィート

56

distinctHQLのdistinctキーワードはSQL のキーワードに直接マップされないことに注意してください。

distinctHQLでキーワードを使用する場合、HibernateはdistinctSQLキーワードを使用することがありますが、状況によっては、結果トランスフォーマーを使用して明確な結果を生成します。たとえば、次のような外部結合を使用している場合:

select distinct o from Order o left join fetch o.lineItems

この場合、SQLレベルで重複を除外することはできません。そのため、SQLクエリが実行された、Hibernateはを使用しResultTransformerて重複を除外します。



16

次回はこのようなことをする

 Criteria crit = (Criteria) session.
                  createCriteria(SomeClass.class).
                  setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

 List claz = crit.list();

それは次善の策です。データベースレベルで繰り返しを破棄するのではなく、繰り返しとすべてを使用してデータベースからメモリにデータをプルし、その後繰り返しを破棄します。データが繰り返される頻度に応じて、I / O操作が大幅に増加する可能性があります。
Haroldo_OK

9

Criteria.DISTINCT_ROOT_ENTITYHibernate HQLクエリでも使用できます。

例:

Query query = getSession().createQuery("from java_pojo_name");
query.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
return query.list();

1
それは次善の策です。データベースレベルで繰り返しを破棄するのではなく、繰り返しとすべてを使用してデータベースからメモリにデータをプルし、その後繰り返しを破棄します。データが繰り返される頻度に応じて、I / O操作が大幅に増加する可能性があります。
Haroldo_OK

4

HQLクエリと組み合わせた結果トランスフォーマーで問題が発生しました。私が試したとき

final ResultTransformer trans = new DistinctRootEntityResultTransformer();
qry.setResultTransformer(trans);

うまくいきませんでした。私はこのように手動で変換する必要がありました:

final List found = trans.transformList(qry.list());

Criteria APIを使用すると、トランスフォーマーは問題なく動作しました。


10kに到達するには(:
timmz 2018年

3

私のメインクエリは、モデルでは次のようになりました。

@NamedQuery(name = "getAllCentralFinancialAgencyAccountCd", 
    query = "select distinct i from CentralFinancialAgencyAccountCd i")

そして、私は私が「明確な」結果と考えていたものをまだ得ていませんでした。これらは、テーブルの主キーの組み合わせに基づいて区別されただけです。

そのDaoImplため、1行の変更を追加し、最終的には「明確な」リターンが得られるようになりました。例としては、00を4回表示するのではなく、1回表示するだけです。これが私が追加したコードですDaoImpl

@SuppressWarnings("unchecked")
public List<CacheModelBase> getAllCodes() {

    Session session = (Session) entityManager.getDelegate();
    org.hibernate.Query q = session.getNamedQuery("getAllCentralFinancialAgencyAccountCd");
    q.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); // This is the one line I had to add to make it do a more distinct query.
    List<CacheModelBase> codes;
    codes = q.list();
    return codes;       
}

これが役に立てば幸いです!繰り返しますが、これは、サービス、DAO、およびプロジェクトのモデルタイプを実装するコーディングプラクティスに従っている場合にのみ機能する可能性があります。


2

CUSTOMER_INFORMATIONテーブルにマップされた顧客エンティティがあり、顧客の個別のfirstNameのリストを取得するとします。同じことを得るには、以下のスニペットを使用できます。

Query distinctFirstName = session.createQuery("select ci.firstName from Customer ci group by ci.firstName");
Object [] firstNamesRows = distinctFirstName.list();

お役に立てば幸いです。したがって、ここでは個別のキーワードを使用する代わりにgroup byを使用しています。

また、以前は、複数の列に適用したい場合に個別のキーワードを使用するのが難しいことに気付きました。たとえば、個別のfirstName、lastName、そしてgroup byのリストを取得したい場合は、単純に機能します。この場合、distinctを使用するのが困難でした。


1

Hibernateクエリ言語でDistinctフィールドを使用するための回答を得ました。* SELECT DISTINCT(TO_CITY)FROM FLIGHT_ROUTE *を使用できます。SQLクエリを使用すると、文字列リストが返されます。Entity Classの戻り値は使用できません。したがって、そのタイプの問題を解決する答えは、SQLでHQL使用することです。

FROM FLIGHT_ROUTE F WHERE F.ROUTE_ID IN (SELECT SF.ROUTE_ID FROM FLIGHT_ROUTE SF GROUP BY SF.TO_CITY);

以下からのSQLクエリステートメントには、リストとしてDISTINCT ROUTE_IDと入力しました。また、INクエリは、IN(リスト)とは異なるTO_CITYをフィルタリングします。

戻り型はエンティティBean型です。したがって、AutoComplementなどのAJAXでそれを行うことができます。

すべて大丈夫です


1

このような条件ビルダーで、個別のキーワードを使用できます。

CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Orders> query = builder.createQuery(Orders.class);
Root<Orders> root = query.from(Orders.class);
query.distinct(true).multiselect(root.get("cust_email").as(String.class));

そして、モデルクラスにフィールドコンストラクターを作成します。


0

selectステートメントでカスタムDTOに新しいキーワードを使用する必要があり、別個の要素が必要場合は、次のようにnewの外でnewを使用します。

select distinct new com.org.AssetDTO(a.id, a.address, a.status) from Asset as a where ...

0

Distinctの代わりにGROUP BYを追加するだけです

@Query(value = "from someTableEntity where entityCode in :entityCode" +
            " group by entityCode, entityName, entityType")
List<someTableEntity > findNameByCode(@Param("entityCode") List<String> entityCode);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.