PostgreSQL
 sql >> डेटाबेस >  >> RDS >> PostgreSQL

पृष्ठांकित पंक्तियाँ और एकल क्वेरी में कुल गणना प्राप्त करें

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

WITH cte AS (
   SELECT * FROM (
      SELECT *, row_number()  -- see below
                OVER (PARTITION BY person_id
                      ORDER BY submission_date DESC NULLS LAST  -- see below
                             , last_updated DESC NULLS LAST  -- see below
                             , id DESC) AS rn
      FROM  tbl
      ) sub
   WHERE  rn = 1
   AND    status IN ('ACCEPTED', 'CORRECTED')
   )
SELECT *, count(*) OVER () AS total_rows_in_cte
FROM   cte
LIMIT  10
OFFSET 0;  -- see below

चेतावनी 1:rank()

rank() प्रति person_id के लिए कई पंक्तियाँ लौटा सकते हैं rank = 1 . के साथ . DISTINCT ON (person_id) (जैसे गॉर्डन प्रदान किया गया) row_number() . के लिए एक लागू प्रतिस्थापन है - जो आपके लिए काम करता है, जैसा कि अतिरिक्त जानकारी स्पष्ट किया गया है। देखें:

चेतावनी 2:ORDER BY submission_date DESC

न तो submission_date न ही last_updated परिभाषित हैं NOT NULL . ORDER BY submission_date DESC, last_updated DESC ... के साथ एक समस्या हो सकती है देखें:

क्या वे कॉलम वास्तव में NOT NULL होने चाहिए? ?

आपने उत्तर दिया:

date . प्रकार के लिए खाली स्ट्रिंग्स की अनुमति नहीं है . कॉलम को अशक्त रखें। NULL उन मामलों के लिए उचित मूल्य है। NULLS LAST Use का उपयोग करें जैसा कि NULL . से बचने के लिए दिखाया गया है शीर्ष पर क्रमबद्ध किया जा रहा है।

चेतावनी 3:OFFSET

अगर OFFSET सीटीई द्वारा लौटाई गई पंक्तियों की संख्या के बराबर या अधिक है, आपको कोई पंक्ति नहीं . मिलती है , इसलिए भी कोई कुल गिनती नहीं है। देखें:

अंतरिम समाधान

अब तक सभी चेतावनियों को संबोधित करते हुए, और अतिरिक्त जानकारी के आधार पर, हम इस प्रश्न पर पहुंच सकते हैं:

WITH cte AS (
   SELECT DISTINCT ON (person_id) *
   FROM   tbl
   WHERE  status IN ('ACCEPTED', 'CORRECTED')
   ORDER  BY person_id, submission_date DESC NULLS LAST, last_updated DESC NULLS LAST, id DESC
   )
SELECT *
FROM  (
   TABLE  cte
   ORDER  BY person_id  -- ?? see below
   LIMIT  10
   OFFSET 0
   ) sub
RIGHT  JOIN (SELECT count(*) FROM cte) c(total_rows_in_cte) ON true;

अब सीटीई असल में है दो बार इस्तेमाल किया। RIGHT JOIN गारंटी है कि हम कुल गिनती प्राप्त करते हैं, कोई फर्क नहीं पड़ता OFFSET . DISTINCT ON प्रति (person_id) . में केवल कुछ पंक्तियों के लिए OK-ish का प्रदर्शन करना चाहिए मूल क्वेरी में।

लेकिन आपके पास विस्तृत पंक्तियाँ हैं। औसतन कितना चौड़ा? क्वेरी के परिणामस्वरूप संपूर्ण तालिका पर क्रमिक स्कैन होने की संभावना है। इंडेक्स मदद नहीं करेंगे (ज्यादा)। यह सब पेजिंग के लिए बेहद अक्षम . रहेगा . देखें:

आप पेजिंग के लिए एक इंडेक्स शामिल नहीं कर सकते क्योंकि यह सीटीई से व्युत्पन्न तालिका पर आधारित है। और पेजिंग के लिए आपका वास्तविक सॉर्ट मानदंड अभी भी स्पष्ट नहीं है (ORDER BY id ?) यदि पेजिंग लक्ष्य है, तो आपको एक अलग क्वेरी शैली की सख्त आवश्यकता है। यदि आप केवल पहले कुछ पृष्ठों में रुचि रखते हैं, तो आपको एक अलग क्वेरी शैली की आवश्यकता है, फिर भी। सबसे अच्छा समाधान उस जानकारी पर निर्भर करता है जो अभी भी प्रश्न में गायब है ...

अत्यधिक तेज़

आपके अपडेट किए गए उद्देश्य के लिए:

("निर्दिष्ट फ़िल्टर मानदंड, प्रकार, योजना, स्थिति के लिए" को अनदेखा करना सादगी के लिए।)

और:

इन दो विशिष्ट सूचकांकों . के आधार पर :

CREATE INDEX ON tbl (submission_date DESC NULLS LAST, last_updated DESC NULLS LAST, id DESC NULLS LAST)
WHERE  status IN ('ACCEPTED', 'CORRECTED'); -- optional

CREATE INDEX ON tbl (person_id, submission_date DESC NULLS LAST, last_updated DESC NULLS LAST, id DESC NULLS LAST);

यह क्वेरी चलाएँ:

WITH RECURSIVE cte AS (
   (
   SELECT t  -- whole row
   FROM   tbl t
   WHERE  status IN ('ACCEPTED', 'CORRECTED')
   AND    NOT EXISTS (SELECT FROM tbl
                      WHERE  person_id = t.person_id 
                      AND   (  submission_date,   last_updated,   id)
                          > (t.submission_date, t.last_updated, t.id)  -- row-wise comparison
                      )
   ORDER  BY submission_date DESC NULLS LAST, last_updated DESC NULLS LAST, id DESC NULLS LAST
   LIMIT  1
   )

   UNION ALL
   SELECT (SELECT t1  -- whole row
           FROM   tbl t1
           WHERE ( t1.submission_date, t1.last_updated, t1.id)
               < ((t).submission_date,(t).last_updated,(t).id)  -- row-wise comparison
           AND    t1.status IN ('ACCEPTED', 'CORRECTED')
           AND    NOT EXISTS (SELECT FROM tbl
                              WHERE  person_id = t1.person_id 
                              AND   (   submission_date,    last_updated,    id)
                                  > (t1.submission_date, t1.last_updated, t1.id)  -- row-wise comparison
                              )
           ORDER  BY submission_date DESC NULLS LAST, last_updated DESC NULLS LAST, id DESC NULLS LAST
           LIMIT  1)
   FROM   cte c
   WHERE  (t).id IS NOT NULL
   )
SELECT (t).*
FROM   cte
LIMIT  10
OFFSET 0;

यहां कोष्ठकों के प्रत्येक सेट की आवश्यकता है।

परिष्कार के इस स्तर को दिए गए सूचकांकों का उपयोग करके और कोई अनुक्रमिक स्कैन नहीं करके शीर्ष पंक्तियों के अपेक्षाकृत छोटे सेट को मौलिक रूप से तेज़ी से प्राप्त करना चाहिए। देखें:

submission_date संभवतः टाइप timestamptz . होना चाहिए या date , नहीं <स्ट्राइक>character varying(255) - जो किसी भी मामले में Postgres में एक विषम प्रकार की परिभाषा है। देखें:

कई और विवरण अनुकूलित किए जा सकते हैं, लेकिन यह हाथ से निकल रहा है। आप पेशेवर परामर्श पर विचार कर सकते हैं।



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. पोस्टग्रेज फंक्शन एंड लूप और रिटर्न एरर

  2. दिनांक मान्य नहीं होने पर त्रुटि उत्पन्न करें

  3. PostgreSQL में किसी विशेष स्कीमा में सभी वस्तुओं के स्वामित्व को कैसे बदलें?

  4. पोस्टग्रेज के साथ स्क्लेल्केमी। 'DISTINCT' के बजाय 'DISTINCT ON' प्राप्त करने का प्रयास करें

  5. PostgreSQL:PostgreSQL डेटाबेस पर किसी उपयोगकर्ता को सभी अनुमतियां दें