आप JPQL या HQL में एक सीमा क्वेरी कैसे करते हैं?


239

हाइबरनेट 3 में, क्या HQL में निम्नलिखित MySQL सीमा के बराबर करने का एक तरीका है?

select * from a_table order by a_table_column desc limit 0, 20;

यदि संभव हो तो मैं setMaxResults का उपयोग नहीं करना चाहता। यह निश्चित रूप से हाइबरनेट / HQL के पुराने संस्करण में संभव था, लेकिन ऐसा लगता है कि यह गायब हो गया है।


2
मैं उपयोग कर रहा हूं Hibernate-5.0.12। क्या यह अभी भी उपलब्ध नहीं है? एक लाख या इतने रिकॉर्ड प्राप्त करना वास्तव में भारी होगा और फिर इस पर फ़िल्टर लागू setMaxResultsकरें- इस पर @Rachel द्वारा @skaffman द्वारा उत्तर में देखा गया।
राजीव रंजन

जवाबों:


313

यह कुछ साल पहले हाइबरनेट फोरम पर पोस्ट किया गया था जब पूछा गया कि यह हाइबरनेट 2 में काम क्यों करता है लेकिन हाइबरनेट 3 में नहीं:

HQL में सीमा कभी भी एक समर्थित क्लाज नहीं थी । आप setMaxResults () का उपयोग करने के लिए हैं।

इसलिए यदि यह हाइबरनेट 2 में काम करता है, तो ऐसा लगता है कि यह संयोग से था, बजाय डिजाइन के। मुझे लगता है यह इसलिए था क्योंकि हाइबरनेट 2 एचक्यूएल पार्सर क्वेरी के बिट्स को बदल देगा जो इसे एचक्यूएल के रूप में मान्यता देता है, और बाकी को छोड़ दें जैसा कि यह था, इसलिए आप कुछ मूल एसक्यूएल में चुपके कर सकते थे। हाइबरनेट 3, हालांकि, एक उचित एएसटी HQL पार्सर है, और यह बहुत कम क्षमा है।

मुझे लगता है कि Query.setMaxResults()वास्तव में आपका एकमात्र विकल्प है।


3
मैं तर्क दूंगा कि हाइबरनेट 3 का दृष्टिकोण अधिक सही है। हाइबरनेट का आपका उपयोग डेटाबेस-एग्नॉस्टिक होने के लिए है, इसलिए आपको इन चीजों को एक सार तरीके से करना चाहिए।
मैट बी

6
मैं सहमत हूं, लेकिन यह गधा में शाही दर्द है जब सुविधाओं को इस तरह से गिरा दिया जाता है।
स्केफमैन

52
लेकिन setMaxResults के साथ, पहले क्वेरी चलाई जाती है और फिर आप setMaxResultsपरिणाम को कॉल करते हैं, जो परिणामी पंक्तियों की सीमित संख्या को परिणाम से लेगा और उपयोगकर्ता को प्रदर्शित करेगा, मेरे मामले में मेरे पास 3 मिलियन रिकॉर्ड हैं जो कि queried हैं और फिर setxaxResults को कॉल करने के लिए सेट किया गया है 50 रिकॉर्ड लेकिन मैं ऐसा नहीं करना चाहता, जबकि खुद को 50 रिकॉर्ड के लिए क्वेरी करना चाहता हूं, क्या ऐसा करने का कोई तरीका है?
राहेल

2
पुरानी पोस्ट जो मुझे पता है। मैं राहेल से पूरी तरह सहमत हूं। NHibernate (। Hibernate के .Net पोर्ट) का उपयोग करते हुए, मैंने हाल ही में 2 से 3 और उसी चीज़ से अपग्रेड किया है, शीर्ष X अब पार्सर त्रुटि फेंक रहा है। हालाँकि, जब मैंने setMaxResults को क्वेरी में जोड़ा, तो इसने परिणामी SQL (MsSql2008Dialect का उपयोग करके) में एक शीर्ष X उत्पन्न किया। यह अच्छा है।
थिएरी_एस 17

17
@Rachel setMaxResultsहाइबरनेट के साथ limitभाग को क्वेरी में जोड़ देगा । इसके सभी परिणाम नहीं मिलेंगे। आप इसे सक्षम करके पैदा होने वाली क्वेरी की जांच कर सकते हैं:<property name="show_sql">true</property>
रसोइयों

148
 // SQL: SELECT * FROM table LIMIT start, maxRows;

Query q = session.createQuery("FROM table");
q.setFirstResult(start);
q.setMaxResults(maxRows);

6
मुझे यह सबसे अच्छा लगता है क्योंकि setFirstResultवास्तव में इस उत्तर में उल्लेख किया गया है, जबकि यहां और कहीं और वे केवल setMaxResultsयह कहते हैं और setMaxResultsयह कि ऑफसेट को कैसे सेट किया जाए, इसका उल्लेख किए बिना।
डेमॉन्गोलम

19

यदि आप ऑब्जेक्ट setMaxResults()पर उपयोग नहीं करना चाहते हैं Queryतो आप हमेशा सामान्य एसक्यूएल का उपयोग करके वापस लौट सकते हैं।


37
यह वास्तव में रोमांचक नहीं है।
स्टीवनब्रोवन

8
मुझे HQL रोमांचक नहीं लगता है। अपने DB सर्वर पर एक दृश्य क्यों न लिखें जो सीमा को लागू करता है और फिर उस दृश्य को देखने के लिए HQL प्राप्त करें: P
pjp

1
यह सिर्फ उन चीजों में से एक है, जबकि एसक्यूएल प्रत्येक क्वेरी के लिए एचक्यूएल की तुलना में बहुत आसान है, विचार बनाने और देशी एसक्यूएल लिखने से रिफैक्टिंग के लिए इतना महान नहीं होता है। जब मैं कर सकता हूं तो मैं इससे बचने की कोशिश करता हूं। यह वास्तविक वास्तविक समस्या थी, मैंने अपनी MySQL क्वेरी को गलत तरीके से लिखा था और सोचा था किMaxResults अजीब हो रहा है। यह नहीं था
१६:०६ पर १०

और यदि आप विभिन्न DBMS विक्रेताओं के बीच स्विच करने की कोशिश करते हैं, तो दर्द आपके लिए इंतजार कर रहा है।
ओल्गुन काया

5

यदि आप setMaxResults का उपयोग नहीं करना चाहते हैं, तो आप सूची के बजाय Query.scroll का उपयोग भी कर सकते हैं, और अपनी इच्छित पंक्तियों को प्राप्त कर सकते हैं। उदाहरण के लिए पेजिंग के लिए उपयोगी है।


धन्यवाद, स्वीकार किए गए उत्तर ने मेरे लिए समस्या का समाधान नहीं किया, क्योंकि setMaxResults()पहले हर रिकॉर्ड को मेमोरी में लोड करता है और फिर एक सबलिस्ट बनाता है, जब सौ हजारों या अधिक रिकॉर्ड सर्वर को क्रैश करते हैं, क्योंकि यह मेमोरी से बाहर है। हालाँकि मैं एक JPA टाइप की गई क्वेरी से एक हाइबरनेट क्वेरी के माध्यम से QueryImpl hibernateQuery = query.unwrap(QueryImpl.class)जा सकता था और फिर मैं scroll()आपके द्वारा सुझाई गई विधि का उपयोग कर सकता था ।
14

कम से कम ओरेकल बोली के साथ यह सच नहीं है (हाइबरनेट ROWNUM वर्चुअल कॉलम का उपयोग करता है)। शायद यह ड्राइवर पर निर्भर करता है। अन्य DBs का TOP फंक्शन है।
लुलिस मार्टिनेज

मेरी क्वेरी एक जॉइन फ़ेच का उपयोग कर रही है। इसका परिणाम हाइबरनेट चेतावनी में होता है "संग्रह के साथ निर्दिष्ट प्रथम / परिणाम / मेमोरी। मेमोरी में आवेदन करना"। एक साथ लाने के लिए, हाइबरनेट मेमोरी में पूर्ण संग्रह लोड कर रहा है। प्रदर्शन कारणों के कारण जॉइन को छोड़ना कोई विकल्प नहीं है। जब मैं स्क्रॉल करने योग्यResults का उपयोग करता हूं, तो मेरे पास अधिक नियंत्रण होता है कि कौन से रिकॉर्ड मेमोरी में लोड किए जाते हैं। मैं सभी रिकॉर्ड्स को एक स्क्रॉल करने योग्य लोड के साथ लोड नहीं कर सकता। क्योंकि इससे मेमोरी भी समाप्त हो जाती है। मैं कई पृष्ठों को अलग-अलग स्क्रॉल करने योग्य लोड करने के लिए प्रयोग कर रहा हूं। अगर यह काम नहीं करता है, तो मैं एसक्यूएल के साथ जाऊंगा।
टॉगल करें

यह अजीब है, मैंने कभी इसका सामना नहीं किया। हाँ कभी-कभी सीधे जेडडीबीसी का उपयोग करने का तरीका है, विशेष रूप से बड़े पैमाने पर / बैच प्रक्रियाओं के लिए।
लूलिस मार्टिनेज

@OneToMany संबंध मेरे मुद्दों का कारण बन रहे हैं। अगर किसी तरह मैं हाइबरनेट में ओरेकल के कुल समारोह LISTAGG को निष्पादित कर सकता हूं, तो एक से अधिक मानों को एक ही मान पर समेटने के लिए, तो मैं जॉइन ड्रॉप कर सकता हूं और उन्हें एक सबक्वेरी द्वारा बदल सकता हूं।
टॉगल करें

2

इसके लिए आप आसानी से पेजिंग का इस्तेमाल कर सकते हैं।

    @QueryHints({ @QueryHint(name = "org.hibernate.cacheable", value = "true") })
    @Query("select * from a_table order by a_table_column desc")
    List<String> getStringValue(Pageable pageable);

आपको new PageRequest(0, 1)रिकॉर्ड लाने के लिए पास करना होगा और सूची से पहला रिकॉर्ड लाना होगा।


2

चूंकि यह एक बहुत ही सामान्य प्रश्न है, इसलिए मैंने यह लेख लिखा है , जिस पर यह उत्तर आधारित है।

setFirstResultऔर setMaxResults Queryतरीकों

एक JPA और हाइबरनेट के लिए Query, setFirstResultविधि के बराबर है OFFSET, और setMaxResultsविधि LIMIT के बराबर है:

List<Post> posts = entityManager
.createQuery(
    "select p " +
    "from Post p " +
    "order by p.createdOn ")
.setFirstResult(10)
.setMaxResults(10)
.getResultList();

LimitHandlerमतिहीनता

हाइबरनेट LimitHandlerडेटाबेस-विशिष्ट पेजिनेशन तर्क को परिभाषित करता है, और जैसा कि निम्नलिखित चित्र द्वारा चित्रित किया गया है, हाइबरनेट कई डेटाबेस-विशिष्ट पेजिनेशन विकल्पों का समर्थन करता है:

<code> LimitHandler </ code> कार्यान्वयन

अब, आपके द्वारा उपयोग किए जा रहे अंतर्निहित रिलेशनल डेटाबेस सिस्टम के आधार पर, उपरोक्त JPQL क्वेरी उचित पेजिनेशन सिंटैक्स का उपयोग करेगी।

माई एसक्यूएल

SELECT p.id AS id1_0_,
       p.created_on AS created_2_0_,
       p.title AS title3_0_
FROM post p
ORDER BY p.created_on
LIMIT ?, ?

PostgreSQL

SELECT p.id AS id1_0_,
       p.created_on AS created_2_0_,
       p.title AS title3_0_
FROM post p
ORDER BY p.created_on
LIMIT ?
OFFSET ?

एस क्यू एल सर्वर

SELECT p.id AS id1_0_,
       p.created_on AS created_on2_0_,
       p.title AS title3_0_
FROM post p
ORDER BY p.created_on
OFFSET ? ROWS 
FETCH NEXT ? ROWS ONLY

आकाशवाणी

SELECT *
FROM (
    SELECT 
        row_.*, rownum rownum_
    FROM (
        SELECT 
            p.id AS id1_0_,
            p.created_on AS created_on2_0_,
            p.title AS title3_0_
        FROM post p
        ORDER BY p.created_on
    ) row_
    WHERE rownum <= ?
)
WHERE rownum_ > ?

उपयोग करने का लाभ setFirstResultऔर setMaxResultsयह है कि हाइबरनेट किसी भी समर्थित रिलेशनल डेटाबेस के लिए डेटाबेस-विशिष्ट पेजिनेशन सिंटैक्स उत्पन्न कर सकता है।

और, आप केवल JPQL प्रश्नों तक ही सीमित नहीं हैं। आप मूल SQL प्रश्नों के लिए setFirstResultऔर setMaxResultsविधि सात का उपयोग कर सकते हैं ।

मूल निवासी SQL प्रश्न

देशी SQL प्रश्नों का उपयोग करते समय आपको डेटाबेस-विशिष्ट पेजिनेशन को हार्डकोड नहीं करना पड़ता है। सीतनिद्रा में होना अपने प्रश्नों को जोड़ सकते हैं।

इसलिए, यदि आप PostgreSQL पर इस SQL ​​क्वेरी को निष्पादित कर रहे हैं:

List<Tuple> posts = entityManager
.createNativeQuery(
    "SELECT " +
    "   p.id AS id, " +
    "   p.title AS title " +
    "from post p " +
    "ORDER BY p.created_on", Tuple.class)
.setFirstResult(10)
.setMaxResults(10)
.getResultList();

हाइबरनेट इसे इस प्रकार रूपांतरित करेगा:

SELECT p.id AS id,
       p.title AS title
FROM post p
ORDER BY p.created_on
LIMIT ?
OFFSET ?

बिल्कुल सटीक?

SQL- आधारित पेजिनेशन से परे

जब आप फ़िल्टरिंग और सॉर्टिंग मानदंडों को अनुक्रमित कर सकते हैं, तो पृष्ठांकन अच्छा है। यदि आपकी पृष्ठांकन आवश्यकताएं गतिशील फ़िल्टरिंग को प्रभावित करती हैं, तो ElasticSearch जैसे इनवर्टेड-इंडेक्स समाधान का उपयोग करना बेहतर तरीका है।

की जाँच करें इस लेख अधिक जानकारी के लिए।


1

String hql = "select userName from AccountInfo order by points desc 5";

यह मेरे लिए उपयोग किए बिना काम किया setmaxResults();

बस कीवर्ड का उपयोग किए बिना अंतिम (इस मामले में 5) में अधिकतम मूल्य प्रदान करें limit। : पी


7
हम्म ... इस बारे में निश्चित नहीं, [उद्धरण वांछित] यह एक दुर्घटना हो सकती है और अचानक हाइबरनेट के नए संस्करण में काम करना बंद कर सकती है।
कोनराड 'ktoso' Malawski

4
कृपया आधिकारिक दस्तावेज देखें।
Do Nhu Vy

1
यह मेरे लिए हाइबरनेट संस्करण
5.2.12 में

1
यह काम नहीं कर रहा है, हाइबरनेट 4.x का भी समर्थन नहीं करता है।
फ़ैज़ अकरम

0

मेरा अवलोकन यह है कि यहां तक ​​कि आपके पास HQL (हाइबरनेट 3.x) में भी सीमा है, यह या तो पार्सिंग त्रुटि का कारण होगा या केवल अनदेखा किया जाएगा। (यदि आपके पास सीमा से पहले + desc / asc का ऑर्डर है, तो इसे अनदेखा कर दिया जाएगा, यदि आपके पास सीमा से पहले desc / asc नहीं है, तो यह पार्सिंग त्रुटि का कारण होगा)


0

यदि इस मोड में एक सीमा का प्रबंधन कर सकते हैं

public List<ExampleModel> listExampleModel() {
    return listExampleModel(null, null);
}

public List<ExampleModel> listExampleModel(Integer first, Integer count) {
    Query tmp = getSession().createQuery("from ExampleModel");

    if (first != null)
        tmp.setFirstResult(first);
    if (count != null)
        tmp.setMaxResults(count);

    return (List<ExampleModel>)tmp.list();
}

यह एक सीमा या सूची को संभालने के लिए एक बहुत ही सरल कोड है।


0
Criteria criteria=curdSession.createCriteria(DTOCLASS.class).addOrder(Order.desc("feild_name"));
                criteria.setMaxResults(3);
                List<DTOCLASS> users = (List<DTOCLASS>) criteria.list();
for (DTOCLASS user : users) {
                System.out.println(user.getStart());
            }

0

तुम्हें पता है, एक देशी क्वेरी लिखने की ज़रूरत उल्लेख इस

@Query(value =
    "SELECT * FROM user_metric UM WHERE UM.user_id = :userId AND UM.metric_id = :metricId LIMIT :limit", nativeQuery = true)
List<UserMetricValue> findTopNByUserIdAndMetricId(
    @Param("userId") String userId, @Param("metricId") Long metricId,
    @Param("limit") int limit);


0

नीचे स्निपेट का उपयोग एचक्यूएल का उपयोग करके सीमा क्वेरी करने के लिए किया जाता है।

Query query = session.createQuery("....");
query.setFirstResult(startPosition);
query.setMaxResults(maxRows);

आप इस लिंक पर डेमो आवेदन प्राप्त कर सकते हैं ।


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.