web-dev-qa-db-ja.com

特定の注文に基づいて休止状態の結果を注文する方法

次のように、特定の文字グループを持つ値を取得するクエリを送信する必要があります。

「XX」に興味があるので、値が「XX」で始まるフィールドまたは「XX」(スペースXX)を持つフィールドを検索する必要があるとします。たとえば、XXCDEFPD XXRFおよびCMKJIEK XXは有効な結果です。

正しい結果が返されますが、並べ替える必要がありますというクエリを最初にXXで最初に返し、次に他の結果を返すようにします。次のように:

XXABCD
XXPLER
XXRFKF
AB XXAB
CD XXCD
ZZ XXOI
POLO XX

コード

Criteria criteria = session.createCriteria(Name.class, "name")
                .add(Restrictions.disjunction()
                     .add(Restrictions.ilike("name.fname", fname + "%"))
                     .add(Restrictions.ilike("name.fname", "%" + " " + fname + "%"))
                    )
                .setProjection(Projections.property("name.fname").as("fname"));
        List<String> names = (List<String>) criteria.list();
23
Jack

JPQL(HQL)を使用

select fname from Name
where upper(fname) like :fnameStart or upper(fname) like :fnameMiddle
order by (case when upper(fname) like :fnameStart then 1 else 2 end), fname

query.setParameter("fnameStart", "XX%");
query.setParameter("fnameMiddle", "% XX%");

基準あり

Criteriaを使用すると、かなりトリッキーになります。まず、order句でネイティブSQLを使用する必要があります。次に、変数をバインドする必要があります。

public class FirstNameOrder extends Order {
    public FirstNameOrder() {
        super("", true);
    }

    @Override
    public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
        return "case when upper(FIRST_NAME) like ? then 1 else 2 end";
    }
}

ケース式の構文とupper関数名は、データベース(もちろん、列名が異なる場合は列名)に従って変更する必要があります。

これをCriteriaに追加するのは簡単ですが、パラメーターをバインドするAPIはありません。

未使用の変数をカスタムSQL制限に渡してHibernateをだまし、order by句の変数に効果的に使用されるようにしました。

Criteria criteria = session.createCriteria(Name.class, "name")
   .add(Restrictions.disjunction()
      .add(Restrictions.ilike("name.fname", fname + "%"))
      .add(Restrictions.ilike("name.fname", "%" + " " + fname + "%")))
   .setProjection(Projections.property("name.fname").as("fname"))
   .add(Restrictions.sqlRestriction("1 = 1", fname + "%", StringType.INSTANCE))
   .addOrder(new FirstNameOrder())
   .addOrder(Order.asc("fname"));

そしてそれはうまくいきます。

明らかに、このソリューションはお勧めできません。このクエリにはJPQLを使用することをお勧めします。

22

HibernateはOrderをサポートしています: http://docs.jboss.org/hibernate/orm/4.2/devguide/en-US/html/ch11.html#ql-ordering 特別な基準のため、 Hibernateで注文をカスタマイズする必要があります。このリンクが役立つ場合があります: http://blog.tremend.ro/2008/06/10/how-to-order-by-a-custom-sql-formulaexpression-when-using-hibernate-criteria-api /

3
Kenny Tai Huynh

2つの選択を実行します。1つは「XX」で始まるすべての文字列に対してフィルタリングされ、もう1つはその他に対してフィルタリングされます。

2
wero

条件で述語を使用できます...このようなもの:

public List<Name> findByParameter(String key, String value, String orderKey)

            CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();
            CriteriaQuery<Name> criteria = builder.createQuery(this.getClazz());
            Root<Name> root = criteria.from(Name.getClass());
            criteria.select(root);
            List<Predicate> predicates = new ArrayList<Predicate>();
            predicates.add(builder.equal(root.get(key), value));
            criteria.where(predicates.toArray(new Predicate[predicates.size()]));
            if (orderKey!=null  && !orderKey.isEmpty()) {
                criteria.orderBy(builder.asc(root.get(orderKey)));
            }
            result = this.entityManager.createQuery(criteria).getResultList();

        return result;
}
1
Gabi Carballo

結果をメモリで並べ替えたくない場合は、条件を変更できます。SQLを表示します

select * from table where fname like 'XX%' order by fname
union all
select * from table where fname like '% XX%' order by fname
union all
select * from table where fname like '% XX' order by fname

結果はあなたの順序でアルファベット順になり、そしてあなたのフィルターを適用します。

0
George

ばかげているが、あなたの場合にはうまくいくかもしれない。

正しい結果が得られたので、次のように結果を再構築できます。

  1. xXで始まるすべての結果をピックアップしてリストL1に入れ、Collections.sort(L1)のような通常のソートを行います。
  2. 他のすべての結果については、L2のリストと同様にCollections.sort(L2)のように実行します。
  3. やっとまとめて

    リストnewList = new ArrayList(L1);

    newList.addAll(L2);

ご注意ください。 Collections.sortは、その要素の自然な順序に従っています。

0
Jegg