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()
बाहरी क्वेरी में कुल कार्य के रूप में। इस मामले में वे सभी एक ही मान में परिणत होते हैं।
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 आज़माएं।