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

केवल न्यूनतम COUNT() के साथ पंक्तियों और स्तंभों (a.k.a. पिवट) को स्थानांतरित करें?

CASE

यदि आपका मामला प्रदर्शित की तरह सरल है, तो एक CASE कथन करेगा:

SELECT year
     , sum(CASE WHEN animal = 'kittens' THEN price END) AS kittens
     , sum(CASE WHEN animal = 'puppies' THEN price END) AS puppies
FROM  (
   SELECT year, animal, avg(price) AS price
   FROM   tab_test
   GROUP  BY year, animal
   HAVING count(*) > 2
   ) t
GROUP  BY year
ORDER  BY year;

इससे कोई फर्क नहीं पड़ता कि आप sum() use का उपयोग करते हैं या नहीं , max() या min() बाहरी क्वेरी में कुल कार्य के रूप में। इस मामले में वे सभी एक ही मान में परिणत होते हैं।

SQL Fiddle

crosstab()

अधिक श्रेणियों के साथ यह crosstab() . के साथ आसान हो जाएगा सवाल। यह बड़ी तालिकाओं के लिए तेज़ भी होना चाहिए ।

आपको अतिरिक्त मॉड्यूल tablefunc इंस्टॉल करना होगा (एक बार प्रति डेटाबेस)। पोस्टग्रेज 9.1 के बाद से यह उतना ही सरल है:

CREATE EXTENSION tablefunc;

इस संबंधित उत्तर में विवरण:

SELECT * FROM crosstab(
      'SELECT year, animal, avg(price) AS price
       FROM   tab_test
       GROUP  BY animal, year
       HAVING count(*) > 2
       ORDER  BY 1,2'

      ,$$VALUES ('kittens'::text), ('puppies')$$)
AS ct ("year" text, "kittens" numeric, "puppies" numeric);

इसके लिए कोई sqlfiddle नहीं है क्योंकि साइट अतिरिक्त मॉड्यूल की अनुमति नहीं देती है।

बेंचमार्क

अपने दावों को सत्यापित करने के लिए मैंने अपने छोटे परीक्षण डेटाबेस में वास्तविक डेटा के करीब एक त्वरित बेंचमार्क चलाया। पोस्टग्रेएसक्यूएल 9.1.6. EXPLAIN ANALYZE . के साथ परीक्षण करें , बेस्ट ऑफ़ 10:

10020 पंक्तियों के साथ परीक्षण सेटअप:

CREATE TABLE tab_test (year int, animal text, price numeric);

-- years with lots of rows
INSERT INTO tab_test
SELECT 2000 + ((g + random() * 300))::int/1000 
     , CASE WHEN (g + (random() * 1.5)::int) %2 = 0 THEN 'kittens' ELSE 'puppies' END
     , (random() * 200)::numeric
FROM   generate_series(1,10000) g;

-- .. and some years with only few rows to include cases with count < 3
INSERT INTO tab_test
SELECT 2010 + ((g + random() * 10))::int/2
     , CASE WHEN (g + (random() * 1.5)::int) %2 = 0 THEN 'kittens' ELSE 'puppies' END
     , (random() * 200)::numeric
FROM   generate_series(1,20) g;

परिणाम:

@bluefeet
कुल रनटाइम:95.401 एमएस

@wildplaser (विभिन्न परिणामों में count <= 3 . के साथ पंक्तियाँ शामिल हैं )
कुल रनटाइम:64.497 एमएस

@Andreiy (+ ORDER BY )
&@Erwin1 - CASE (दोनों लगभग समान प्रदर्शन करते हैं)
कुल रनटाइम:39.105 एमएस

@Erwin2 - crosstab()
कुल रनटाइम:17.644 ms

बड़े पैमाने पर आनुपातिक (लेकिन अप्रासंगिक) परिणाम केवल 20 पंक्तियों के साथ होते हैं। केवल @wildplasser के CTE में अधिक ओवरहेड और थोड़ा स्पाइक होता है।

मुट्ठी भर से अधिक पंक्तियों के साथ, crosstab() जल्दी से आगे बढ़ जाता है। @ आंद्रेई की क्वेरी मेरे सरलीकृत संस्करण के समान ही प्रदर्शन करती है, बाहरी SELECT में कुल कार्य करता है (min() , max() , sum() ) कोई औसत दर्जे का अंतर नहीं करता है (प्रति समूह केवल दो पंक्तियाँ)।

सब कुछ उम्मीद के मुताबिक, कोई आश्चर्य नहीं, मेरा सेटअप लें और इसे @home आज़माएं।



  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. Postgresql जहां खंड में एकल उद्धरण से बचता है

  3. Postgres . में टाइमस्टैम्प को एक पूर्णांक (यूनिक्स युग) में कैसे परिवर्तित करें

  4. SQL में LOOP को शामिल करना

  5. वेबिनार :पोस्टग्रेएसक्यूएल 11 में नई सुविधाएँ [फॉलो अप]