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

प्रति समूह पहली और अंतिम पंक्ति से मान प्राप्त करें

कई सरल और तेज़ तरीके हैं।

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 को अनुकूलित करें


  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 9.2 pg_dump संस्करण बेमेल

  3. PostgreSQL क्वेरी इंडेक्स स्कैन के साथ तेजी से चलती है, लेकिन इंजन हैश जॉइन चुनता है

  4. एक समारोह में चयन या INSERT दौड़ की स्थिति के लिए प्रवण है?

  5. PostgreSQL 12 . के लिए डेटाबेस प्रबंधन और निगरानी