कई सरल और तेज़ तरीके हैं।
2x DISTINCT ON
SELECT *
FROM (
SELECT DISTINCT ON (name)
name, week AS first_week, value AS first_val
FROM tbl
ORDER BY name, week
) f
JOIN (
SELECT DISTINCT ON (name)
name, week AS last_week, value AS last_val
FROM tbl
ORDER BY name, week DESC
) l USING (name);
या छोटा:
SELECT *
FROM (SELECT DISTINCT ON (1) name, week AS first_week, value AS first_val FROM tbl ORDER BY 1,2) f
JOIN (SELECT DISTINCT ON (1) name, week AS last_week , value AS last_val FROM tbl ORDER BY 1,2 DESC) l USING (name);
सरल और समझने में आसान। मेरे पुराने परीक्षणों में भी सबसे तेज़। DISTINCT ON
. के लिए विस्तृत विवरण :
- समूह द्वारा प्रत्येक समूह में पहली पंक्ति का चयन करें?
2x विंडो फ़ंक्शन, 1x DISTINCT ON
SELECT DISTINCT ON (name)
name, week AS first_week, value AS first_val
, first_value(week) OVER w AS last_week
, first_value(value) OVER w AS last_value
FROM tbl t
WINDOW w AS (PARTITION BY name ORDER BY week DESC)
ORDER BY name, week;
स्पष्ट WINDOW
क्लॉज केवल कोड को छोटा करता है, प्रदर्शन पर कोई प्रभाव नहीं पड़ता।
first_value()
मिश्रित प्रकार का
कुल कार्य min()
या max()
समग्र प्रकारों को इनपुट के रूप में स्वीकार न करें। आपको कस्टम समुच्चय फ़ंक्शन बनाना होगा (जो इतना कठिन नहीं है)।
लेकिन विंडो कार्य करती है first_value()
और last_value()
करें . इसके आधार पर हम सरल समाधान तैयार कर सकते हैं:
साधारण क्वेरी
SELECT DISTINCT ON (name)
name, week AS first_week, value AS first_value
,(first_value((week, value)) OVER (PARTITION BY name ORDER BY week DESC))::text AS l
FROM tbl t
ORDER BY name, week;
आउटपुट में सभी डेटा होते हैं, लेकिन पिछले सप्ताह के मान एक अनाम रिकॉर्ड में भर दिए जाते हैं (वैकल्पिक रूप से text
पर डाला जाता है) ) आपको विघटित मूल्यों की आवश्यकता हो सकती है।
तालिका प्रकार के अवसरवादी उपयोग के साथ विघटित परिणाम
उसके लिए हमें एक प्रसिद्ध समग्र प्रकार की आवश्यकता है। एक अनुकूलित तालिका परिभाषा सीधे तालिका प्रकार के अवसरवादी उपयोग की अनुमति देगी:
CREATE TABLE tbl (week int, value int, name text); -- optimized column order
week
और value
पहले आओ, इसलिए अब हम टेबल प्रकार के अनुसार ही छाँट सकते हैं:
SELECT (l).name, first_week, first_val
, (l).week AS last_week, (l).value AS last_val
FROM (
SELECT DISTINCT ON (name)
week AS first_week, value AS first_val
, first_value(t) OVER (PARTITION BY name ORDER BY week DESC) AS l
FROM tbl t
ORDER BY name, week
) sub;
उपयोगकर्ता द्वारा परिभाषित पंक्ति प्रकार से विघटित परिणाम
ज्यादातर मामलों में शायद यह संभव नहीं है। CREATE TYPE
. के साथ कंपोजिट टाइप रजिस्टर करें (स्थायी) या CREATE TEMP TABLE
. के साथ (सत्र की अवधि के लिए):
CREATE TEMP TABLE nv(last_week int, last_val int); -- register composite type
SELECT name, first_week, first_val, (l).last_week, (l).last_val
FROM (
SELECT DISTINCT ON (name)
name, week AS first_week, value AS first_val
, first_value((week, value)::nv) OVER (PARTITION BY name ORDER BY week DESC) AS l
FROM tbl t
ORDER BY name, week
) sub;
कस्टम समग्र कार्य first()
&last()
प्रति डेटाबेस एक बार फ़ंक्शन और समुच्चय बनाएँ:
CREATE OR REPLACE FUNCTION public.first_agg (anyelement, anyelement)
RETURNS anyelement
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE AS
'SELECT $1;'
CREATE AGGREGATE public.first(anyelement) (
SFUNC = public.first_agg
, STYPE = anyelement
, PARALLEL = safe
);
CREATE OR REPLACE FUNCTION public.last_agg (anyelement, anyelement)
RETURNS anyelement
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE AS
'SELECT $2';
CREATE AGGREGATE public.last(anyelement) (
SFUNC = public.last_agg
, STYPE = anyelement
, PARALLEL = safe
);
फिर:
SELECT name
, first(week) AS first_week, first(value) AS first_val
, last(week) AS last_week , last(value) AS last_val
FROM (SELECT * FROM tbl ORDER BY name, week) t
GROUP BY name;
शायद सबसे सुरुचिपूर्ण समाधान। अतिरिक्त मॉड्यूल के साथ तेज़ first_last_agg
सी कार्यान्वयन प्रदान करना।
पोस्टग्रेज विकी में निर्देशों की तुलना करें।
संबंधित:
- प्रत्येक प्रभावशाली व्यक्ति के लिए समय के साथ अनुयायी वृद्धि की गणना करना
db<>यहां बेला करें (सभी दिखा रहा है)
पुराना sqlfiddle
इनमें से प्रत्येक प्रश्न EXPLAIN ANALYZE
के साथ 50k पंक्तियों वाली तालिका पर एक त्वरित परीक्षण में वर्तमान में स्वीकृत उत्तर की तुलना में काफी तेज़ था ।
और भी तरीके हैं। डेटा वितरण के आधार पर, विभिन्न क्वेरी शैलियाँ (बहुत) तेज़ हो सकती हैं, फिर भी। देखें:
- प्रति उपयोगकर्ता नवीनतम पंक्ति पुनर्प्राप्त करने के लिए क्वेरी द्वारा GROUP को अनुकूलित करें