मैं कुशलतापूर्वक "सबसे हाल की संगत पंक्ति" कैसे प्राप्त करूं?


53

मेरे पास एक क्वेरी पैटर्न है जो बहुत सामान्य होना चाहिए, लेकिन मुझे नहीं पता कि इसके लिए एक कुशल क्वेरी कैसे लिखनी है। मैं एक तालिका की पंक्तियों को देखना चाहता हूं जो "किसी अन्य तालिका की पंक्तियों के बाद सबसे हाल की तारीख" के अनुरूप है।

मेरे पास एक मेज है, inventoryकहते हैं, जो एक निश्चित दिन में मेरे पास मौजूद इन्वेंट्री का प्रतिनिधित्व करता है।

date       | good | quantity
------------------------------
2013-08-09 | egg  | 5
2013-08-09 | pear | 7
2013-08-02 | egg  | 1
2013-08-02 | pear | 2

और एक मेज, "कीमत" कहती है, जो एक निश्चित दिन में एक अच्छी कीमत रखती है

date       | good | price
--------------------------
2013-08-07 | egg  | 120
2013-08-06 | pear | 200
2013-08-01 | egg  | 110
2013-07-30 | pear | 220

मैं इन्वेंट्री टेबल की प्रत्येक पंक्ति के लिए "सबसे हाल ही में" कुशलता से कैसे प्राप्त कर सकता हूं , अर्थात

date       | pricing date | good | quantity | price
----------------------------------------------------
2013-08-09 | 2013-08-07   | egg  | 5        | 120
2013-08-09 | 2013-08-06   | pear | 7        | 200
2013-08-02 | 2013-08-01   | egg  | 1        | 110
2013-08-02 | 2013-07-30   | pear | 2        | 220

मुझे यह करने का एक तरीका पता है:

select inventory.date, max(price.date) as pricing_date, good
from inventory, price
where inventory.date >= price.date
and inventory.good = price.good
group by inventory.date, good

और फिर इस क्वेरी को फिर से इन्वेंट्री में शामिल करें । बड़ी क्वेरी के लिए भी पहली क्वेरी ( इन्वेंट्री में फिर से शामिल किए बिना ) बहुत धीमी है। हालाँकि, एक ही समस्या जल्दी से हल हो जाती है यदि मैं बस सूची तालिका से max(price.date) ... where price.date <= date_of_interest ... order by price.date desc limit 1प्रत्येक के लिए एक क्वेरी जारी करने के लिए अपनी प्रोग्रामिंग भाषा का उपयोग करता हूं date_of_interest, तो मुझे पता है कि कोई कम्प्यूटेशनल बाधा नहीं है। हालाँकि, मैं पूरी समस्या को एक एकल SQL क्वेरी के साथ हल करना पसंद करूंगा, क्योंकि यह मुझे क्वेरी के परिणाम पर आगे SQL प्रसंस्करण करने की अनुमति देगा।

क्या इसे कुशलता से करने का एक मानक तरीका है? ऐसा लगता है कि यह अक्सर ऊपर आना चाहिए और इसके लिए एक तेज क्वेरी लिखने का एक तरीका होना चाहिए।

मैं Postgres का उपयोग कर रहा हूं, लेकिन SQL-जेनेरिक उत्तर की सराहना की जाएगी।


3
यह DBA.SE में माइग्रेट किया जाना है क्योंकि यह एक दक्षता प्रश्न है। हम क्वेरी को कुछ अलग तरीकों से लिख सकते हैं, लेकिन यह इसे बहुत तेज़ नहीं बनाएगा।
ypercube y

5
क्या आपको वास्तव में एक ही प्रश्न से सभी दिनों के लिए सभी सामानों की आवश्यकता है? एक अपेक्षित आवश्यकता की तरह लगता है? आम तौर पर एक विशिष्ट तिथि के लिए कीमतों को फिर से प्राप्त किया जाएगा या एक विशिष्ट अच्छा (विशिष्ट तिथि पर) के लिए मूल्य। उन वैकल्पिक प्रश्नों से बहुत अधिक आसानी से (उपयुक्त) सूचकांकों का लाभ मिल सकता है। हमें यह भी जानना चाहिए: कार्डिनैलिटीज़ (प्रत्येक तालिका में कितनी पंक्तियाँ?), पूर्ण तालिका परिभाषा झुकाव। डेटा प्रकार, बाधाएं, सूचकांक, ... ( \d tblpsql में उपयोग ), पोस्टग्रेज और मिनट का आपका संस्करण । / अधिकतम। प्रति अच्छे दामों की संख्या।
इरविन ब्रान्डसेट्टर

@ErwinBrandstetter क्या आप मुझसे एक जवाब स्वीकार करने के लिए कह रहे हैं? मैं वास्तव में यह जानने के लिए योग्य नहीं हूं कि कौन सा सबसे अच्छा है, हालांकि आपका सबसे अधिक उत्थान है, मैं इसे स्वीकार करने में प्रसन्न हूं।
टॉम एलिस

केवल तभी स्वीकार करें जब यह आपके प्रश्न का उत्तर देता है या आपके लिए काम करता है। आप एक टिप्पणी भी छोड़ सकते हैं कि आप कैसे आगे बढ़े यदि वह संबंधित मामलों में मदद कर सके। यदि आपको लगता है कि आपका प्रश्न अनुत्तरित है, तो हमें बताएं।
एरविन ब्रान्डसेट्टर

1
मुझे तब माफी मांगनी होगी, क्योंकि हालांकि मुझे यह मिला है कि जो उत्कृष्ट उत्तर प्रतीत होते हैं, मैं अब उस समस्या पर काम नहीं कर रहा हूं, जिसने प्रश्न को उकसाया है इसलिए मैं न्याय करने के लिए किसी जगह पर नहीं हूं जो सबसे अच्छा उत्तर है, या यदि वास्तव में उनमें से कोई है मेरे उपयोग के मामले के लिए वास्तव में उपयुक्त हैं (जैसा कि यह था)। अगर कुछ DBA.Stackexchange ettiquette है तो मुझे इस मामले में पालन करना चाहिए कृपया मुझे बताएं।
टॉम एलिस

जवाबों:


42

यह बहुत कुछ परिस्थितियों और सटीक आवश्यकताओं पर निर्भर करता हैप्रश्न के लिए मेरी टिप्पणी पर विचार करें ।

सरल उपाय

साथ DISTINCT ONPostgres में:

SELECT DISTINCT ON (i.good, i.the_date)
       i.the_date, p.the_date AS pricing_date, i.good, p.price
FROM   inventory  i
LEFT   JOIN price p ON i.good = p.good AND i.the_date >= p.the_date
ORDER  BY i.good, i.the_date, p.the_date DESC;

परिणाम का आदेश दिया।

या NOT EXISTSमानक SQL में (हर RDBMS के साथ काम करता है जो मुझे पता है):

SELECT i.the_date, p.the_date AS pricing_date, i.good, i.quantity, p.price
FROM   inventory  i
LEFT   JOIN price p ON p.good = i.good AND p.the_date <= i.the_date
WHERE  NOT EXISTS (
   SELECT 1 FROM price p1
   WHERE  p1.good = p.good
   AND p1.the_date <= i.the_date
   AND p1.the_date >  p.the_date
   );

समान परिणाम, लेकिन मनमाने ढंग से क्रम के साथ - जब तक आप नहीं जोड़ते ORDER BY
डेटा वितरण, सटीक आवश्यकताओं और सूचकांकों के आधार पर, इनमें से एक भी तेज हो सकता है।
आम तौर पर, DISTINCT ONविजेता होता है और आपको इसके शीर्ष पर एक हल किया गया परिणाम मिलता है। लेकिन कुछ मामलों के लिए अन्य क्वेरी तकनीक (बहुत) तेज, फिर भी हैं। निचे देखो।

अधिकतम / मिनट मूल्यों की गणना करने के लिए उपश्रेणियों के साथ समाधान आम तौर पर धीमे होते हैं। सीटीई वाले वेरिएंट आमतौर पर धीमे होते हैं, फिर भी।

सादा विचार (जैसे एक अन्य उत्तर द्वारा प्रस्तावित) पोस्टग्रेज़ में प्रदर्शन में मदद नहीं करता है।

एसक्यूएल फिडल।


उचित समाधान

तार और टकराव

सबसे पहले, आप एक उप-इष्टतम तालिका लेआउट से पीड़ित हैं। यह तुच्छ लग सकता है, लेकिन अपने स्कीमा को सामान्य करने से बहुत लंबा रास्ता तय किया जा सकता है।

से अनुक्रमित चरित्र प्रकार ( text, varchar, ...) - स्थान के अनुसार किया जा सकता है COLLATION विशेष रूप से। सबसे अधिक संभावना है कि आपका DB नियमों के कुछ स्थानीय सेटों का उपयोग करता है (जैसे, मेरे मामले में:) de_AT.UTF-8। इसके साथ पता करें:

SHOW lc_collate;

यह सॉर्टिंग और इंडेक्स लुक-अप को धीमा बनाता है । अब आपके तार (सामानों के नाम) बदतर हैं। यदि आप वास्तव में अपने आउटपुट में टकराव के नियमों (या सभी प्रकार के क्रम) की परवाह नहीं करते हैं, तो यह तेजी से हो सकता है यदि आप जोड़ते हैं COLLATE "C":

SELECT DISTINCT ON (i.good COLLATE "C", i.the_date)
       i.the_date, p.the_date AS pricing_date, i.good, p.price
FROM   inventory  i
LEFT   JOIN price p ON i.good = p.good AND i.the_date >= p.the_date
ORDER  BY i.good COLLATE "C", i.the_date, p.the_date DESC;

ध्यान दें कि मैंने दो स्थानों पर टकराव को कैसे जोड़ा।
20k पंक्तियों के साथ मेरे परीक्षण में दो बार तेज और बहुत मूल नाम ('123 ')।

सूची

यदि आपकी क्वेरी किसी इंडेक्स का उपयोग करने वाली है, तो वर्ण डेटा वाले कॉलमों का मिलान मिलान ( goodउदाहरण में) करना होता है:

CREATE INDEX inventory_good_date_desc_collate_c_idx
ON price(good COLLATE "C", the_date DESC);

SO पर इस संबंधित उत्तर के अंतिम दो अध्यायों को अवश्य पढ़ें:

यहां तक ​​कि एक ही कॉलम पर अलग-अलग कोलाज के साथ आपके पास कई इंडेक्स हो सकते हैं - यदि आपको अन्य प्रश्नों के अनुसार किसी अन्य (या डिफ़ॉल्ट) कोलेशन के अनुसार सॉर्ट किए गए सामान की भी आवश्यकता है।

सामान्य

निरर्थक तार (अच्छे का नाम) आपके टेबल और इंडेक्स को भी फूला देते हैं, जिससे सब कुछ धीमा हो जाता है। एक उचित तालिका लेआउट के साथ आप शुरू करने के लिए अधिकांश समस्या से बच सकते हैं। इस तरह देख सकते हैं:

CREATE TABLE good (
  good_id serial PRIMARY KEY
, good    text   NOT NULL
);

CREATE TABLE inventory (
  good_id  int  REFERENCES good (good_id)
, the_date date NOT NULL
, quantity int  NOT NULL
, PRIMARY KEY(good_id, the_date)
);

CREATE TABLE price (
  good_id  int     REFERENCES good (good_id)
, the_date date    NOT NULL
, price    numeric NOT NULL
, PRIMARY KEY(good_id, the_date));

प्राथमिक कुंजी स्वचालित रूप से हमारी आवश्यकता के सभी सूचकांकों को प्रदान करती है (लगभग)।
लापता विवरण के आधार पर, एक एकाधिक सूचकांक पर priceदूसरे स्तंभ पर अवरोही क्रम के प्रदर्शन में सुधार कर सकते हैं के साथ:

CREATE INDEX price_good_date_desc_idx ON price(good, the_date DESC);

फिर से, टकराव आपकी क्वेरी से मेल खाना चाहिए (ऊपर देखें)।

9.2 या बाद में इंडेक्स-ओनली स्कैन के लिए "कवरिंग इंडेक्स" में कुछ और मदद कर सकता है - खासकर अगर आपकी टेबल अतिरिक्त कॉलम रखती हैं, जिससे टेबल कवरिंग इंडेक्स से काफी बड़ी हो जाती है।

ये परिणामी प्रश्न बहुत तेज हैं:

अस्तित्व में नहीं है

SELECT i.the_date, p.the_date AS pricing_date, g.good, i.quantity, p.price
FROM   inventory  i
JOIN   good       g USING (good_id)
LEFT   JOIN price p ON p.good_id = i.good_id AND p.the_date <= i.the_date
AND    NOT EXISTS (
   SELECT 1 FROM price p1
   WHERE  p1.good_id = p.good_id
   AND    p1.the_date <= i.the_date
   AND    p1.the_date >  p.the_date
   );

DISTINCT ON

SELECT DISTINCT ON (i.the_date)
       i.the_date, p.the_date AS pricing_date, g.good, i.quantity, p.price
FROM   inventory  i
JOIN   good       g USING (good_id)
LEFT   JOIN price p ON p.good_id = i.good_id AND p.the_date <= i.the_date
ORDER  BY i.the_date, p.the_date DESC;

एसक्यूएल फिडल।


तेजी से समाधान

यदि वह अभी भी तेजी से पर्याप्त नहीं है, तो तेजी से समाधान हो सकते हैं।

पुनरावर्ती CTE / JOIN LATERAL/ सहसंबद्ध उपश्रेणी

विशेष रूप से अच्छे मूल्य के साथ कई डेटा वितरण के लिए :

भौतिकवादी दृश्य

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

Postgres 9.3+ में भौतिक विचारों के लिए स्वचालित समर्थन है। आप पुराने संस्करणों में आसानी से एक मूल संस्करण लागू कर सकते हैं।


3
price_good_date_desc_idxसूचकांक आप नाटकीय रूप से अनुशंसा करते हैं मेरा एक समान क्वेरी के लिए प्रदर्शन में सुधार किया। मेरी क्वेरी योजना 42374.01..42374.86नीचे की लागत से चली गई 0.00..37.12!
साइमन

@ साइमन: अच्छा! आपकी मुख्य क्वेरी विशेषता क्या है? अस्तित्व में नहीं है? DISTINCT ON? समूह द्वारा?
इरविन ब्रान्डेसटेटर

DISTINCT पर उपयोग
cimmanon

6

FYI करें, मैंने mssql 2008 का उपयोग किया, इसलिए Postgres में "शामिल" सूचकांक नहीं होगा। हालांकि, आप नीचे देख सकते बुनियादी अनुक्रमण का उपयोग कर हैश से बदल जाएगा विलय करने के लिए मिलती है Postgres में मिलती है: http://explain.depesz.com/s/eF6 (कोई इंडेक्स) http://explain.depesz.com/s/j9x ( शामिल होने के मानदंडों पर सूचकांक के साथ)

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

create view mostrecent_pricing_dates_per_good as
select i.good,i.date i_date,max(p.date)p_date
  from inventory i
  join price p on i.good = p.good and i.date >= p.date
 group by i.good,i.date;

फिर आपकी क्वेरी अन्य प्रकारों के लिए हेरफेर करने के लिए सरल और आसान हो सकती है यदि जांच (जैसे कि हाल ही की तारीखों के बिना इन्वेंट्री को खोजने के लिए बाएं जोड़ों का उपयोग करना):

select i.good
       ,i.date inventory_date
       ,i.quantity
       ,p.date pricing_date
       ,p.price       
  from inventory i
  join price p on i.good = p.good
  join mostrecent_pricing_dates_per_good x 
    on i.good = x.good 
   and p.date = x.p_date
   and i.date = x.i_date

यह निम्नलिखित निष्पादन योजना देता है: http://sqlfiddle.com/# -3/24f23/1 कोई अनुक्रमण नहीं

... सभी पूरी तरह से स्कैन करते हैं। हैश मैचों की सूचना प्रदर्शन लागत कुल लागत के थोक तक ले जाती है ... और हम जानते हैं कि टेबल स्कैन और सॉर्ट धीमी हैं (लक्ष्य की तुलना में: सूचकांक चाहता है)।

अब, अपने अनुक्रमणिका में उपयोग किए गए मानदंड में मदद करने के लिए बुनियादी अनुक्रमित जोड़ें (मैं कोई दावा नहीं करता कि ये इष्टतम सूचकांक हैं, लेकिन वे इस बिंदु को चित्रित करते हैं): http://sqlfiddle.com/# ! -3/5ec75/1 बुनियादी अनुक्रमण के साथ

यह सुधार दिखाता है। नेस्टेड लूप (आंतरिक जुड़ाव) ऑपरेशन अब क्वेरी के लिए कोई प्रासंगिक कुल लागत नहीं लेते हैं। बाकी की लागत अब सूचकांक के बीच फैली हुई है (इन्वेंट्री के लिए एक स्कैन क्योंकि हम हर इन्वेंट्री पंक्ति को खींच रहे हैं)। लेकिन हम अभी भी बेहतर कर सकते हैं क्योंकि क्वेरी मात्रा और मूल्य खींचती है। उस डेटा को प्राप्त करने के लिए, जॉइंट क्रिटेरा का मूल्यांकन करने के बाद, लुकअप प्रदर्शन करना होगा।

इंडेक्स पर अंतिम पुनरावृत्ति "शामिल" का उपयोग करता है ताकि योजना को खत्म करने और इंडेक्स के अतिरिक्त डेटा का अधिकार प्राप्त करने में आसानी हो सके। तो लुकअप चले गए हैं: http://sqlfiddle.com/#! -3/5f143 /1 यहाँ छवि विवरण दर्ज करें

अब हमारे पास एक क्वेरी योजना है जहां क्वेरी की कुल लागत समान रूप से बहुत तेज़ इंडेक्स की तलाश के संचालन के बीच फैली हुई है। यह के रूप में अच्छा-के रूप में यह करीब हो जाएगा। निश्चित रूप से अन्य विशेषज्ञ इसे और बेहतर कर सकते हैं, लेकिन समाधान कुछ प्रमुख चिंताओं को दूर करता है:

  1. यह आपके डेटाबेस में समझदार डेटा संरचनाएं बनाता है जो किसी अनुप्रयोग के अन्य क्षेत्रों में रचना और पुन: उपयोग करना आसान होता है।
  2. सभी सबसे महंगी क्वेरी ऑपरेटरों को कुछ मूल अनुक्रमण का उपयोग करके क्वेरी योजना से बाहर रखा गया है।

3
यह ठीक है (एसक्यूएल-सर्वर के लिए) लेकिन अलग-अलग डीबीएमएस के लिए अनुकूलन जबकि इसमें समानताएं हैं, इसके साथ ही गंभीर अंतर भी हैं।
ypercube y

@ypercube जो सच है। मैंने पोस्टग्रेज के बारे में कुछ योग्यताएँ जोड़ीं। मेरा अभिप्राय यह था कि यहाँ वर्णित अधिकांश प्रक्रिया डीबीएमएस विशिष्ट विशेषताओं की परवाह किए बिना लागू होगी।
cocogorilla

उत्तर बहुत गहराई में है, इसलिए मुझे इसे आज़माने में थोड़ा समय लगेगा। मैं आपको बता दूंगा कि मैं कैसे आगे बढ़ता हूं।
टॉम एलिस

5

यदि आपके पास PostgreSQL 9.3 (आज जारी किया गया) है तो आप एक LATERAL JOIN का उपयोग कर सकते हैं।

मेरे पास इसका परीक्षण करने का कोई तरीका नहीं है, और पहले कभी भी इसका उपयोग नहीं किया है, लेकिन मैं प्रलेखन से जो बता सकता हूं वह वाक्य रचना कुछ इस तरह होगा:

SELECT  Inventory.Date,
        Inventory.Good,
        Inventory.Quantity,
        Price.Date,
        Price.Price
FROM    Inventory
        LATERAL
        (   SELECT  Date, Price
            FROM    Price
            WHERE   Price.Good = Inventory.Good
            AND     Price.Date <= Inventory.Date
            ORDER BY Price.Date DESC
            LIMIT 1
        ) p;

यह मूल रूप से SQL-Server के APPLY के बराबर है , और डेमो उद्देश्यों के लिए SQL-Fiddle पर इसका एक कार्यशील उदाहरण है।


5

जैसा कि इरविन और अन्य ने नोट किया है, एक कुशल क्वेरी बहुत सारे वेरिएबल्स पर निर्भर करती है और पोस्टग्रेक्यूएल उन वेरिएबल्स के आधार पर क्वेरी एक्जीक्यूशन को ऑप्टिमाइज़ करने की बहुत कोशिश करता है। सामान्य तौर पर आप पहले स्पष्टता के लिए लिखना चाहते हैं और बाद में बाधाओं की पहचान करने के बाद प्रदर्शन के लिए संशोधित करते हैं।

इसके अतिरिक्त PostgreSQL में बहुत सारी तरकीबें हैं जिनका उपयोग आप चीजों को थोड़ा और अधिक कुशल बनाने के लिए कर सकते हैं (एक के लिए आंशिक अनुक्रमित) ताकि आपके पढ़ने / लिखने के भार के आधार पर, आप सावधानीपूर्वक अनुक्रमण को देखकर इसे बहुत दूर तक अनुकूलित कर सकें।

कोशिश करने के लिए पहली बात सिर्फ एक दृश्य करना और इसमें शामिल होना है:

CREATE VIEW most_recent_rows AS
SELECT good, max(date) as max_date
FROM inventory
GROUP BY good;

ऐसा करते समय कुछ अच्छा करना चाहिए:

SELECT price 
  FROM inventory i
  JOIN goods g ON i.goods = g.description
  JOIN most_recent_rows r ON i.goods = r.goods
 WHERE g.id = 123;

तब आप इसमें शामिल हो सकते हैं। क्वेरी अंतर्निहित तालिका के विरुद्ध दृश्य में शामिल होना समाप्त कर देगी, लेकिन यह मानते हुए कि आपके पास एक अद्वितीय अनुक्रमणिका है (दिनांक, उस क्रम में अच्छा ), आपको जाने के लिए अच्छा होना चाहिए (क्योंकि यह एक साधारण कैश लुकअप होगा)। यह कुछ पंक्तियों के साथ बहुत अच्छी तरह से काम करेगा, लेकिन अगर आप माल की लाखों कीमतों को पचाने की कोशिश कर रहे हैं तो यह बहुत अक्षम होगा।

दूसरी चीज जो आप कर सकते हैं वह है इन्वेंट्री टेबल को एक most_recent बूल कॉलम और

create unique index on inventory (good) where most_recent;

जब आप किसी अच्छे के लिए एक नई पंक्ति सम्मिलित की जाती है, तो आप सबसे अधिक सेट करने के लिए ट्रिगर का उपयोग करना चाहेंगे। यह बग के लिए अधिक जटिलता और अधिक संभावना जोड़ता है लेकिन यह मददगार है।

फिर से इसमें से बहुत कुछ उचित अनुक्रमित पर निर्भर करता है। अधिकांश हाल की तारीख के प्रश्नों के लिए, आपके पास संभवतः दिनांक पर एक सूचकांक होना चाहिए, और संभव है कि एक बहु-स्तंभ तिथि के साथ शुरू हो और जिसमें आपके मानदंड शामिल हों।

नीचे प्रति इरविन की टिप्पणी को अपडेट करें, ऐसा लगता है कि मैंने इसे गलत समझा। प्रश्न को फिर से पढ़ना मैं बिल्कुल भी निश्चित नहीं हूं कि क्या पूछा जा रहा है। मैं अद्यतन में उल्लेख करना चाहता हूं कि मुझे क्या संभावित समस्या है और यह इस अस्पष्टता को क्यों छोड़ता है।

पेश किए गए डेटाबेस डिज़ाइन का ERP और लेखा प्रणालियों के साथ कोई वास्तविक उपयोग IME नहीं है। यह एक काल्पनिक आदर्श मूल्य निर्धारण मॉडल में काम करेगा जहां किसी दिए गए उत्पाद के दिए गए दिन में सभी चीजें बेची जाती हैं। हालांकि, यह मामला हमेशा नहीं होता है। यह मुद्रा विनिमय जैसी चीजों के लिए भी मामला नहीं है (हालांकि कुछ मॉडल यह दिखावा करते हैं कि यह करता है)। यदि यह एक विरोधाभासी उदाहरण है, तो यह स्पष्ट नहीं है। यदि यह एक वास्तविक उदाहरण है, तो डेटा स्तर पर डिज़ाइन के साथ बड़ी समस्याएं हैं। मैं यहां यह मानने जा रहा हूं कि यह एक वास्तविक उदाहरण है।

आप यह नहीं मान सकते कि अकेले तारीख किसी अच्छे के लिए मूल्य निर्दिष्ट करती है। किसी भी व्यवसाय में कीमतें प्रति-पार्टी और यहां तक ​​कि कभी-कभी प्रति लेन-देन पर भी बातचीत की जा सकती हैं। इस कारण से आपको वास्तव में उस तालिका में मूल्य संग्रहित करना चाहिए जो वास्तव में इन्वेंट्री को इन या आउट (इन्वेंट्री टेबल) को संभालती है। ऐसे मामले में आपकी तारीख / सामान / मूल्य तालिका केवल एक आधार मूल्य निर्दिष्ट करती है जो बातचीत के आधार पर परिवर्तन के अधीन हो सकती है। ऐसे मामले में यह समस्या एक रिपोर्टिंग समस्या होने से होती है, जो एक समय में प्रत्येक तालिका से एक पंक्ति में लेन-देन और संचालन होती है। उदाहरण के लिए, आप किसी दिए गए उत्पाद के लिए दिए गए दिन के लिए डिफ़ॉल्ट मूल्य देख सकते हैं:

 SELECT price 
   FROM prices p
   JOIN goods g ON p.good = g.good
  WHERE g.id = 123 AND p."date" >= '2013-03-01'
  ORDER BY p."date" ASC LIMIT 1;

कीमतों पर सूचकांक (अच्छी, तारीख) के साथ यह अच्छा प्रदर्शन करेगा।

मैं यह एक विरोधाभासी उदाहरण हूं, शायद आप जिस चीज पर काम कर रहे हैं उसके करीब कुछ मदद करेगा।


most_recentदृष्टिकोण सबसे हाल ही में कीमत के लिए अच्छी तरह से काम करना चाहिए बिल्कुल । ऐसा लगता है कि प्रत्येक इन्वेंट्री की तारीख के सापेक्ष ओपी को सबसे हाल की कीमत की आवश्यकता है , हालांकि।
इरविन ब्रान्डसेट्टर

अच्छी बात। पुन: पढ़ना हालांकि मैं प्रस्तावित डेटा के साथ कुछ वास्तविक व्यावहारिक कमियों को देखता हूं, लेकिन मैं यह नहीं बता सकता कि क्या यह केवल एक आकस्मिक उदाहरण है। एक उदाहरण के रूप में, मैं नहीं बता सकता कि क्या गायब है। शायद यह इंगित करने के लिए एक अद्यतन भी क्रम में होगा।
क्रिस ट्रैवर्स

@ क्रिसट्रावर्स: यह एक आकस्मिक उदाहरण है, लेकिन मैं उस वास्तविक स्कीमा को पोस्ट करने के लिए स्वतंत्र नहीं हूं, जिसके साथ मैं काम कर रहा हूं। शायद आप थोड़ा सा कह सकते हैं कि आपने किन व्यावहारिक कमियों को देखा है।
टॉम एलिस

मुझे नहीं लगता कि इसे सटीक होने की आवश्यकता है, लेकिन रूपक में खो जाने की समस्या के बारे में चिंतित हैं। थोड़ा सा करीब मददगार होगा। मुद्दा यह है कि मूल्य निर्धारण के साथ, एक निश्चित दिन की कीमत एक डिफ़ॉल्ट होने की संभावना है, और परिणामस्वरूप आप इसे केवल लेनदेन प्रविष्टि के लिए एक डिफ़ॉल्ट के रूप में रिपोर्ट करने के लिए उपयोग नहीं करेंगे, इसलिए आपके दिलचस्प प्रश्न आम तौर पर केवल कुछ पंक्तियों में हैं समय।
क्रिस ट्रैवर्स

3

एक और तरीका यह होगा कि lead()टेबल मूल्य में प्रत्येक पंक्ति के लिए तिथि सीमा प्राप्त करने के लिए विंडो फ़ंक्शन का उपयोग किया betweenजाए और फिर इन्वेंट्री में शामिल होने पर उपयोग किया जाए। मैंने वास्तव में वास्तविक जीवन में इसका उपयोग किया है, लेकिन मुख्य रूप से यह मेरा पहला विचार था कि इसे कैसे हल किया जाए।

with cte as (
  select
    good,
    price,
    date,
    coalesce(lead(date) over(partition by good order by date) - 1
            ,Now()::date) as ndate
  from
    price
)

select * from inventory i join cte on
  (i.good = cte.good and i.date between cte.date and cte.ndate)

SqlFiddle


1

इन्वेंट्री से मूल्य में शामिल होने के लिए एक ऐसी स्थिति का उपयोग करें, जो कीमत टैब से rec ords को केवल उन लोगों तक सीमित कर दे, जो इन्वेंट्री की तारीख पर या उससे पहले हैं, फिर अधिकतम तिथि निकालें, और उस तारीख को उस सबसेट से उच्चतम तिथि कहां है

तो अपनी सूची मूल्य के लिए:

 Select i.date, p.Date pricingDate,
    i.good, quantity, price        
 from inventory I join price p 
    on p.good = i.good
        And p.Date = 
           (Select Max(Date from price
            where good = i.good
               and date <= i.Date)

यदि किसी निर्दिष्ट अच्छे के लिए कीमत एक ही दिन में एक से अधिक बार बदल गई, और आपके पास वास्तव में केवल तारीखें हैं और इन स्तंभों में कोई समय नहीं है, तो आपको कीमत परिवर्तन रिकॉर्ड्स में से केवल एक का चयन करने के लिए जोड़ों पर अधिक प्रतिबंध लगाने की आवश्यकता हो सकती है।


दुर्भाग्य से चीजों को गति देने के लिए प्रतीत नहीं होता है।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.