2012-03-23 14 views
12

मेरे पास 'छात्र' नामक डेटाबेस तालिका है जिसमें 'अंक' नामक एक कॉलम है। मैं गणित में उच्चतम अंकों के साथ छात्र रिकॉर्ड चाहता हूँ। इसमें order_by()[0] उपयोग करने के लिए एक सरल उपाय है:Django: अधिकतम तत्व के साथ रिकॉर्ड

Student.objects.filter(subject='Maths').order_by('-marks')[0] 

लेकिन इस तालिका सॉर्ट करता है और फिर मुझे पहले रिकॉर्ड को हासिल करेगा। अगर मेरी मेज बड़ी है, तो यह अनावश्यक है क्योंकि मुझे केवल अधिकतम रिकॉर्ड की आवश्यकता है। सॉर्ट किए बिना सबसे बड़ा मूल्य प्राप्त करने का कोई तरीका है?

मैं पूरी वस्तु ही नहीं, अधिकतम मूल्य चाहते हैं।

धन्यवाद अनुज

उत्तर

22

एसक्यूएल आवश्यक कुछ इस तरह होगा:

SELECT * 
FROM STUDENT 
WHERE marks = (SELECT MAX(marks) FROM STUDENT) 

Django के माध्यम से ऐसा करने के लिए, आप aggregation API उपयोग कर सकते हैं।

max_marks = Student.objects.filter(
    subject='Maths' 
).aggregate(maxmarks=Max('marks'))['maxmarks'] 
Student.objects.filter(subject='Maths', marks=max_marks) 

दुर्भाग्य से, यह प्रश्न वास्तव में दो प्रश्न हैं। अधिकतम चिह्न एकत्रीकरण निष्पादित किया जाता है, परिणाम पायथन में खींचा जाता है, फिर दूसरी क्वेरी में भेज दिया जाता है। वहां (आश्चर्यजनक रूप से) कोई क्वेरीसेट पास करने का कोई तरीका नहीं है जो समूह के बिना एक समेकन है, भले ही इसे करना संभव हो। मैं यह देखने के लिए टिकट खोलने जा रहा हूं कि यह कैसे तय किया जा सकता है।

संपादित करें:

यह संभव किसी एक क्वेरी के साथ ऐसा करना है, लेकिन यह बहुत स्पष्ट नहीं है। मैंने इस विधि को कहीं और नहीं देखा है।

from django.db.models import Value 

max_marks = (
    Student.objects 
      .filter(subject='Maths') 
      .annotate(common=Value(1)) 
      .values('common') 
      .annotate(max_marks=Max('marks')) 
      .values('max_marks') 
) 

Student.objects.filter(subject='Maths', marks=max_marks) 

आप खोल में इस क्वेरी प्रिंट तो आपको मिलेगा:

SELECT 
     "scratch_student"."id", 
     "scratch_student"."name", 
     "scratch_student"."subject", 
     "scratch_student"."marks" 
    FROM "scratch_student" 
WHERE ( 
     "scratch_student"."subject" = Maths 
    AND "scratch_student"."marks" = (
     SELECT 
       MAX(U0."marks") AS "max_marks" 
     FROM "scratch_student" U0 
     WHERE U0."subject" = Maths)) 

Django 1.11 (अल्फा में वर्तमान में) पर परीक्षण किया गया। यह निरंतर 1 द्वारा एनोटेशन को समूहीकृत करके काम करता है, जिसमें प्रत्येक पंक्ति समूहबद्ध होगी। इसके बाद हम इस समूह को कॉलम को चुनिंदा सूची (दूसरे values()) से अलग करते हैं। Django (अब) यह निर्धारित करने के लिए पर्याप्त जानता है कि समूह अनावश्यक है, और इसे हटा देता है। सटीक एसक्यूएल के साथ एक ही क्वेरी छोड़कर हमें चाहिए।

+0

क्या है एफ में एफ ('max_mark')? –

+0

@ चाडवर्नन, उन्हें एफ() अभिव्यक्ति कहा जाता है। वे आपको किसी अन्य कॉलम के मान का उपयोग करने की अनुमति देते हैं। https://docs.djangoproject.com/en/dev/topics/db/queries/#query-expressions –

+2

यह काम नहीं करता है। परिणामी एसक्यूएल कुछ ऐसा है: 'चयन *, MAX ("चिह्न") छात्र "छात्र" से "max_mark" के रूप में "मार्क" = (MAX ("छात्र"। "अंक"))', जो बस सभी का चयन करता है छात्रों। –

2

यह सवाल आप के लिए मददगार हो सकते हैं: How to do SELECT MAX in Django?

बस एकत्रीकरण का उपयोग करें।

from django.db.models import Max 
Student.objects.filter(subject='Math').aggregate(Max('marks')) 

परीक्षण नहीं किया गया है, लेकिन काम करना चाहिए। :)

0

बेवकूफ डेटाबेस तालिका, सैद्धांतिक रूप से कोई संभावित तरीका नहीं है कि डेटाबेस पहले सॉर्टिंग के बिना आपके लिए अधिकतम मूल्य पुनर्प्राप्त कर सकता है। बस इसके बारे में सोचें, डेटाबेस को कैसे पता चलेगा कि अधिकतम मूल्य क्या है जब तक कि यह प्रत्येक पंक्ति पर न देखा जाए?

बेशक, यह एक बहुत ही बेवकूफ सेटअप के साथ है। सौभाग्य से आपके पास दो विकल्प उपलब्ध हैं:

  1. एक सूचकांक का उपयोग करें। यदि आप उस कॉलम पर एक इंडेक्स बनाते हैं, तो सॉर्टिंग आमतौर पर इंडेक्स का लाभ ले सकती है - आपको एक पूर्ण टेबल स्कैन सहेजती है।

  2. सामान्यीकृत (उर्फ प्रीकंप्यूट)। किसी अन्य तालिका को कहीं भी बनाएँ जो अधिकतम मान संग्रहीत करता है, और सुनिश्चित करें कि जब भी छात्र ऑब्जेक्ट जोड़ा/संशोधित/हटा दिया जाता है तो आप इसे चेक/अपडेट करते हैं।

अधिक आवश्यकताओं को जानने के बिना, मैं दृढ़ता से सूचकांक का उपयोग करने का सुझाव देता हूं।

चेक आउट: https://docs.djangoproject.com/en/dev/ref/models/fields/#db-index

+0

यह प्रश्न Django ORM के बारे में अधिक प्रतीत होता है और वास्तव में डेटाबेस या तालिका संरचनाओं के बारे में नहीं, जो आपका उत्तर दिशा में केंद्रित है। – TheCatParty

+1

सैद्धांतिक रूप से, अधिकतम खोजना एक ओ (एन) ऑपरेशन है - आपको बस एक बार प्रत्येक तत्व पर जाना होगा जो सॉर्टिंग से अलग है। सॉर्ट करने के लिए आपको ओ (nlogn) तुलना करने की आवश्यकता है। – abhaga

+0

@abhaga डेटाबेस की प्राथमिक लक्ष्य, मेरी राय में, तेजी से डेटा पहुंच की अनुमति देना है। एक इंडेक्स बनाकर, डेटाबेस को सॉर्ट किया जाता है ताकि अधिकतम (या न्यूनतम, या ऑफसेट) तक पहुंच एक ओ (1) ऑपरेशन हो। –

संबंधित मुद्दे