2009-09-23 14 views
5

मेरे पास एक सारणी है जिसे मैं "वाई से बाहर रैंक एक्स" डेटा प्रस्तुत करने में सक्षम होना चाहता हूं। विशेष रूप से, मैं उस डेटा को अपेक्षाकृत कुशल तरीके से एक व्यक्तिगत पंक्ति के लिए प्रस्तुत करने में सक्षम होना चाहता हूं (यानी तालिका में प्रत्येक पंक्ति का चयन किए बिना)। रैंकिंग स्वयं काफी सरल है, यह तालिका में एक ही कॉलम पर सीधे आदेश है।मुझे PostgreSQL में "वाई से बाहर रैंक एक्स" डेटा को कैसे संभालना चाहिए?

पोस्टग्रेस इस संबंध में कुछ अनूठी चुनौतियों का सामना करना प्रतीत होता है; AFAICT में उसके पास रैंक या ROW_NUMBER या समकक्ष फ़ंक्शन नहीं है (कम से कम 8.3 में, जिसे मैं इस पल के लिए फंस गया हूं)।

test=> create temporary sequence tmp_seq; 
CREATE SEQUENCE 
test=*> select nextval('tmp_seq') as row_number, col1, col2 from foo; 

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

मैं रैंक को एक अलग कॉलम में डिमॉर्मलाइज और स्टोर कर सकता हूं, जो डेटा को छोटा करता है, लेकिन मेरी समस्या को स्थानांतरित करता है। अद्यतन द्वारा आदेश का समर्थन नहीं करता है, इसलिए मुझे यकीन नहीं है कि मैं रैंक सेट करने के लिए एक अद्यतन क्वेरी कैसे बनाऊंगा (प्रत्येक पंक्ति का चयन करने और प्रत्येक पंक्ति के लिए एक अलग अद्यतन चलाने के लिए, जो कि बहुत अधिक डीबी गतिविधि की तरह लगता है हर बार रैंक को अद्यतन करने की आवश्यकता होती है)।

क्या मुझे कुछ याद आ रही है? ऐसा करने का सही तरीका क्या है?

संपादित करें: स्पष्ट रूप से मैं पर्याप्त स्पष्ट नहीं था। मुझे ऑफसेट/एलआईटी के बारे में पता है, लेकिन मुझे नहीं लगता कि यह इस समस्या को हल करने में कैसे मदद करता है। मैं Xth- रैंकिंग आइटम का चयन करने की कोशिश नहीं कर रहा हूं, मैं एक मनमानी आइटम (अपने पीके द्वारा कहने के लिए) चुनने की कोशिश कर रहा हूं, और फिर उपयोगकर्ता को "312 में से 43 वें स्थान पर" प्रदर्शित करने में सक्षम हूं।

उत्तर

6

आप रैंक चाहते हैं,

SELECT id,num,rank FROM (
    SELECT id,num,rank() OVER (ORDER BY num) FROM foo 
) AS bar WHERE id=4 

की तरह कुछ करने या आप अगर वास्तव में पंक्ति संख्या चाहते हैं,

SELECT id,num,row_number FROM (
    SELECT id,num,row_number() OVER (ORDER BY num) FROM foo 
) AS bar WHERE id=4 
का उपयोग करें

जब आपके पास बराबर मूल्य हों तो वे अलग-अलग होंगे।अगर आपको इसकी ज़रूरत है तो dense_rank() भी है।

इसके लिए पोस्टग्रेएसक्यूएल 8.4 की आवश्यकता है।

+0

वह वाक्यविन्यास निश्चित रूप से बहुत अच्छा है। शायद मुझे यह विचार करना होगा कि इसे अपग्रेड करने के लिए क्या करना होगा। –

+0

अभी तक, मुझे कभी-कभी डिज़ाइन किए गए डेटाबेस के साथ अपग्रेड करने में कोई समस्या नहीं आई है, जबकि लाभ असंख्य हैं। हालांकि, मेरे ग्राहकों में से एक ने पाया कि नई 'हैशएग्रेगेट' विधि के साथ, 'DISTINCT' अब जरूरी नहीं है कि उसके कुछ प्रश्न तोड़ दिए। यह निश्चित रूप से दोषी है, लेकिन सुनिश्चित करें कि आपके प्रश्न इन चाल पर भरोसा नहीं करते हैं। – Quassnoi

+0

मूल प्रश्न 8.3 निर्दिष्ट है, लेकिन मैंने फैसला किया कि यह इन कार्यों तक पहुंच प्राप्त करने के लिए 8.4 तक अपग्रेड करने योग्य था। महान काम करना, उत्तर के लिए धन्यवाद! –

3

ROW_NUMBER PostgreSQL में कार्यक्षमता LIMIT n OFFSET skip के माध्यम से लागू की गई है।

  • एक सिंहावलोकन here खोजें।
  • रैंकिंग के नुकसान पर this SO question देखें।

संपादित करें: यदि आप ROW_NUMBER() सरल रैंकिंग के बजाय के लिए पूछ रहे हैं के बाद से: row_number() संस्करण 8.4 में PostgreSQL के लिए शुरू की है। तो आप अपडेट करने पर विचार कर सकते हैं। अन्यथा this workaround सहायक हो सकता है।

+0

मुझे डुप्लिकेट मुद्दों और सावधानी बरतने के बारे में पता है। यह मेरे प्रश्न का बिल्कुल जवाब नहीं देता है।LIMIT और OFFSET का उपयोग करना काफी आसान है, लेकिन मुझे साइट पर प्रदर्शित करने के लिए रैंकिंग नंबर नहीं देता है ("यह आइटम 312 में से 43 वां स्थान पर है"), जो कि संपूर्ण बिंदु है। –

4

है ना सिर्फ इस:

SELECT * 
FROM mytable 
ORDER BY 
     col1 
OFFSET X LIMIT 1 

या मैं कुछ याद आ रही है?

अद्यतन:

आप रैंक को दिखाने के लिए चाहते हैं, इस का उपयोग करें:

SELECT mi.*, values[1] AS rank, values[2] AS total 
FROM (
     SELECT (
       SELECT ARRAY[SUM(((mi.col1, mi.ctid) < (mo.col1, mo.ctid))::INTEGER), COUNT(*)] 
       FROM mytable mi 
       ) AS values 
     FROM mytable mo 
     WHERE mo.id = @myid 
     ) q 
+0

बीटन 1 सेकेंड द्वारा। फिर भी आप सही हैं। +1 –

+0

ऐसा लगता है कि यह मुझे पीटा गया है: आपके उत्तर की आईडी आईडी '1' से छोटी है :) – Quassnoi

+0

ऊपर टिप्पणी देखें; मुझे नहीं लगता कि आप मेरे प्रश्न को समझ गए हैं। अगर मैं 12 वीं रैंकिंग वाली वस्तु का चयन करना चाहता हूं तो ऑफ़सेट/LIMIT बहुत अच्छा है। लेकिन मैं नहीं करता। मैं आईडी 37 के साथ आइटम का चयन करना चाहता हूं, और साइट पर "यह आइटम 312 में से 43 वें स्थान पर प्रदर्शित" प्रदर्शित करना चाहता हूं। मैं नहीं देखता कि ऑफसेट/LIMIT वहां कैसे मदद करता है। –

1

पिछला उत्तर से निपटने के सवाल "सभी पंक्तियों को चुनें और उनके रैंक प्राप्त" जो नहीं है कि आप क्या चाहते ...

  • आप एक पंक्ति
  • आप अपनी रैंक में जानना चाहते है

बस कार्य करें:

चयन गिनती (*) तालिका से कहां स्कोर> $ 1

जहां $ 1 आपके द्वारा चुने गए पंक्ति का स्कोर है (मुझे लगता है कि आप इसे प्रदर्शित करना चाहते हैं ताकि आप इसे चुन सकें ...)।

या करें:

एक चुनें। , रैंक के रूप में (टेबल ख कहां स्कोर> b.score से गणना () का चयन करें) तालिका से एक कहां पी = ...

हालांकि, अगर आप एक पंक्ति जो पिछले वें स्थान पर है, का चयन हाँ आप की आवश्यकता होगी इससे पहले कि सभी पंक्तियों को रैंक किया गया है, उन्हें गिनने के लिए, इसलिए आपको पूरी तालिका स्कैन करने की आवश्यकता होगी, और यह बहुत धीमी होगी।

समाधान:

चयन गिनती (*) से

आप 30 सर्वश्रेष्ठ स्कोर के लिए सटीक रैंकिंग मिलेगा (तालिका कहां स्कोर> $ 1 सीमा 30 से चयन 1), और यह तेजी से हो जाएगा। कौन हारे हुए लोगों की परवाह करता है?

ठीक है, तुम सच में हारे के बारे में देखभाल करते हैं, आप एक हिस्टोग्राम बनाने की आवश्यकता होगी:

मान लीजिए स्कोर 0 से 100 तक जा सकते हैं, और आप के साथ < 80 और 10 विजेताओं स्कोर के साथ 1000000 हारे है स्कोर> 80.

आप एक्स के स्कोर के कितने पंक्तियों का हिस्टोग्राम बनाते हैं, यह 100 पंक्तियों वाली एक साधारण छोटी तालिका है। हिस्टोग्राम को अद्यतन करने के लिए अपनी मुख्य तालिका में एक ट्रिगर जोड़ें।

अब अगर आप एक हारे हुए जो स्कोर एक्स है रैंक करने के लिए चाहते हैं, अपने स्तर से राशि (histo) जहां histo_score> एक्स

है के बाद से अपने स्कोर को शायद 0 से 100 के बीच नहीं है, लेकिन (माना) के बीच 0 और 1000000000, उदाहरण के लिए, आपको थोड़ा सा झुकाव करना होगा, अपने हिस्टोग्राम डिब्बे को बढ़ाएं। इसलिए आपको केवल 100 डिब्बे अधिकतम की आवश्यकता है, या कुछ लॉग-हिस्टोग्राम वितरण फ़ंक्शन का उपयोग करें।

रास्ता postgres करके करता है जब आप तालिका विश्लेषण, इसलिए यदि आप स्कोर पर 100 या 1000 के लिए statistics_target निर्धारित करते हैं, विश्लेषण, और उसके बाद चलाएँ:

तालिका से चयन * बताएं स्कोर> $ 1

आपको एक अच्छा पंक्ति गणना अनुमान मिलेगा।

किसके लिए सही उत्तर की आवश्यकता है?

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