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

औसत स्टॉक इतिहास तालिका

विशेष कठिनाई इस कार्य का:आप केवल अपनी समय सीमा के भीतर डेटा बिंदु नहीं चुन सकते हैं, लेकिन नवीनतम पर विचार करना होगा डेटा बिंदु पहले समय सीमा और जल्द से जल्द डेटा बिंदु बाद अतिरिक्त समय सीमा। यह प्रत्येक पंक्ति के लिए भिन्न होता है और प्रत्येक डेटा बिंदु मौजूद हो भी सकता है और नहीं भी। एक परिष्कृत क्वेरी की आवश्यकता है और अनुक्रमणिका का उपयोग करना कठिन बनाता है।

आप श्रेणी के प्रकार का उपयोग कर सकते हैं और ऑपरेटर (पोस्टग्रेज 9.2+ ) गणनाओं को सरल बनाने के लिए:

WITH input(a,b) AS (SELECT '2013-01-01'::date  -- your time frame here
                         , '2013-01-15'::date) -- inclusive borders
SELECT store_id, product_id
     , sum(upper(days) - lower(days))                    AS days_in_range
     , round(sum(value * (upper(days) - lower(days)))::numeric
                    / (SELECT b-a+1 FROM input), 2)      AS your_result
     , round(sum(value * (upper(days) - lower(days)))::numeric
                    / sum(upper(days) - lower(days)), 2) AS my_result
FROM (
   SELECT store_id, product_id, value, s.day_range * x.day_range AS days
   FROM  (
      SELECT store_id, product_id, value
           , daterange (day, lead(day, 1, now()::date)
             OVER (PARTITION BY store_id, product_id ORDER BY day)) AS day_range 
      FROM   stock
      ) s
   JOIN  (
      SELECT daterange(a, b+1) AS day_range
      FROM   input
      ) x ON s.day_range && x.day_range
   ) sub
GROUP  BY 1,2
ORDER  BY 1,2;

ध्यान दें, मैं कॉलम नाम day . का उपयोग करता हूं date . के बजाय . मैं स्तंभ नामों के रूप में मूल प्रकार के नामों का कभी भी उपयोग नहीं करता।

सबक्वेरी में sub मैं विंडो फ़ंक्शन के साथ प्रत्येक आइटम के लिए अगली पंक्ति से दिन लाता हूं lead() , "आज" को डिफ़ॉल्ट रूप से प्रदान करने के लिए अंतर्निहित विकल्प का उपयोग करते हुए जहां कोई अगली पंक्ति नहीं है।
इसके साथ मैं एक daterange बनाता हूं और इसे इनपुट के साथ ओवरलैप ऑपरेटर && . के साथ मिलाएं , परिणामी दिनांक सीमा की गणना चौराहे ऑपरेटर * . के साथ करें

यहां सभी श्रेणियां अनन्य . के साथ हैं ऊपरी सीमा। इसलिए मैं एक दिन इनपुट रेंज में जोड़ता हूं। इस तरह हम आसानी से lower(range) . को घटा सकते हैं upper(range) . से दिनों की संख्या प्राप्त करने के लिए।

मुझे लगता है कि "कल" ​​विश्वसनीय डेटा के साथ नवीनतम दिन है। "आज" अभी भी वास्तविक जीवन के अनुप्रयोग में बदल सकता है। नतीजतन, मैं "आज" (now()::date . का उपयोग करता हूं ) खुली सीमाओं के लिए अनन्य ऊपरी सीमा के रूप में।

मैं दो परिणाम प्रदान करता हूं:

  • your_result आपके प्रदर्शित परिणामों से सहमत हैं।
    आप बिना शर्त अपनी तिथि सीमा में दिनों की संख्या से विभाजित करते हैं। उदाहरण के लिए, यदि कोई आइटम केवल अंतिम दिन के लिए सूचीबद्ध है, तो आपको बहुत कम (भ्रामक!) "औसत" मिलता है।

  • my_result समान या उच्चतर संख्याओं की गणना करता है।
    मैं वास्तविक . से विभाजित करता हूं किसी आइटम के सूचीबद्ध होने के दिनों की संख्या. उदाहरण के लिए, यदि कोई आइटम केवल अंतिम दिन के लिए सूचीबद्ध है, तो मैं सूचीबद्ध मान को औसत के रूप में वापस कर देता हूं।

अंतर को समझने के लिए मैंने आइटम के सूचीबद्ध होने के दिनों की संख्या को जोड़ा:days_in_range

SQL Fiddle

सूचकांक और प्रदर्शन

इस प्रकार के डेटा के लिए, पुरानी पंक्तियाँ आमतौर पर नहीं बदलती हैं। यह एक भौतिक दृश्य . के लिए एक उत्कृष्ट मामला बन जाएगा :

CREATE MATERIALIZED VIEW mv_stock AS
SELECT store_id, product_id, value
     , daterange (day, lead(day, 1, now()::date) OVER (PARTITION BY store_id, product_id
                                                       ORDER BY day)) AS day_range
FROM   stock;

फिर आप एक GiST इंडेक्स जोड़ सकते हैं जो संबंधित ऑपरेटर का समर्थन करता है && :

CREATE INDEX mv_stock_range_idx ON mv_stock USING gist (day_range);

बड़ा परीक्षण मामला

मैंने 200k पंक्तियों के साथ अधिक यथार्थवादी परीक्षण चलाया। एमवी का उपयोग करने वाली क्वेरी लगभग 6 गुना तेज थी, जो कि @ जोप की क्वेरी से ~ 10x तेज थी। प्रदर्शन काफी हद तक डेटा वितरण पर निर्भर करता है। एक एमवी बड़ी टेबल और प्रविष्टियों की उच्च आवृत्ति के साथ सबसे अधिक मदद करता है। साथ ही, यदि तालिका में ऐसे कॉलम हैं जो इस क्वेरी के लिए प्रासंगिक नहीं हैं, तो एमवी छोटा हो सकता है। लागत बनाम लाभ का प्रश्न।

मैंने अब तक पोस्ट किए गए सभी समाधानों (और अनुकूलित) को खेलने के लिए एक बड़ी पहेली में डाल दिया है:

SQL Fiddle with big test case.
SQL Fiddle केवल 40k पंक्तियों के साथ - sqlfiddle.com पर टाइमआउट से बचने के लिए



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. psycopg2 R dbWriteTable कमांड के बराबर है और अजगर कोड से अधिक प्रदर्शन प्राप्त कर रहा है

  2. सबस्ट्रिंग के लिए pg_search मणि ​​का उपयोग करके रेल पर पीजी पूर्ण पाठ खोज

  3. postgresql कई अवधियों को एक में मिलाता है

  4. pg_stat_statements के साथ बड़े सांख्यिकीय सेट एकत्रित करना?

  5. PostgreSQL में संख्या प्रकार के रूप में अंतराल को माइक्रोसेकंड में बदलें?