एक सीमा में हर तारीख के लिए एक जटिल प्रश्न चल रहा है


9

मुझे आदेशों की एक तालिका मिल गई है

   Column   |            Type             |                      Modifiers                      
------------+-----------------------------+-----------------------------------------------------
 id         | integer                     | not null default nextval('orders_id_seq'::regclass)
 client_id  | integer                     | not null
 start_date | date                        | not null
 end_date   | date                        | 
 order_type | character varying           | not null

डेटा के पास क्लाइंट_id के लिए नॉन ओवरलैपिंग स्टैंडिंग ऑर्डर होते हैं और कभी-कभी एक अस्थायी ऑर्डर होता है जो उस पर खड़े ऑर्डर को ओवरराइड करता है, जब उनके पास एक क्लाइंट क्लाइंट होता है। ओवरलैपिंग से एक ही प्रकार के ऑर्डर रखने पर एप्लिकेशन स्तर की बाधाएं हैं।

 id | client_id | start_date |  end_date  | order_type 
----+-----------+------------+------------+------------
 17 |        11 | 2014-02-05 |            | standing
 18 |        15 | 2014-07-16 | 2015-07-19 | standing
 19 |        16 | 2015-04-01 |            | standing
 20 |        16 | 2015-07-18 | 2015-07-18 | temporary

उदाहरण के लिए, 2015-07-18क्लाइंट 16 पर ऑर्डर # 20 है क्योंकि यह सक्रिय ऑर्डर है क्योंकि यह स्टैंडिंग ऑर्डर # 19 को ओवरराइड करता है। कुछ उपद्रव के साथ मुझे डेट पर सक्रिय ऑर्डर आईडी के लिए क्वेरी करने का एक कुशल तरीका मिला।

    SELECT id from (
      SELECT
        id,
        first_value(id) OVER (PARTITION BY client_id ORDER BY order_type DESC) active_order_id
      FROM orders
      WHERE start_date <= ? and (end_date is null OR end_date >= ?)
    ) active_orders
    WHERE id = active_order_id

यदि आप इसे 2015-07-18प्लेसहोल्डर्स के साथ क्वेरी करते हैं , तो आपको मिलेगा

 id 
----
 17
 18
 20

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

अब, मुझे उन तिथियों के लिए सभी सक्रिय आदेशों को खोजने की आवश्यकता है, जो उन तिथियों के साथ सम्मिलित हैं, जिन पर वे सक्रिय हैं। उदाहरण के लिए, I की तिथि सीमा के 2015-07-18साथ 2015-07-19मैं निम्नलिखित परिणाम चाहूंगा।

active_date | id 
------------+----
 2015-07-18 | 17
 2015-07-18 | 18
 2015-07-18 | 20
 2015-07-19 | 17
 2015-07-19 | 18
 2015-07-19 | 19

आदेश 20 पर आदेश 19 को ओवरराइड करता है, 2015-07-18पर नहीं 2015-07-19

मैंने पाया कि generate_series()मैं तारीखों की एक श्रृंखला उत्पन्न कर सकता हूं, लेकिन मुझे इस बात का कोई सुराग नहीं है कि तारीखों की एक तालिका प्राप्त करने और आईडी के क्रम में इसके साथ कैसे जुड़ें। मेरा कूबड़ एक क्रॉस जॉइन है लेकिन मैं यह नहीं समझ सकता कि इस परिस्थिति में उस काम को कैसे किया जाए।

धन्यवाद

अद्यतन एक एसक्यूएल बेला जोड़ा गया ।


2
क्या आप कुछ उदाहरण डेटा दिखा सकते हैं? यह सक्रिय / गैर-सक्रिय और अस्थायी चीजें पहले पढ़ने के बाद बहुत स्पष्ट नहीं हैं।
dezso

हां, यह स्पष्ट नहीं है। आपकी क्वेरी को प्रति ग्राहक एक ऑर्डर मिलेगा और यह नियतात्मक नहीं लगता है। यदि किसी क्लाइंट के लिए 2 या अधिक ऑर्डर हैं, तो एक ही प्रकार के साथ, दोनों में से जो भी लौटाया जाएगा वह मनमाना होगा और प्रति निष्पादन अलग-अलग होगा। तो, आपके पास या तो टेबल पर कुछ अड़चनें हैं जो आपने हमें नहीं बताई हैं या आपकी क्वेरी सही नहीं है।
ypercube y

मैंने अपने प्रश्न को बहुत अधिक विवरणों के साथ अद्यतन किया, और हाँ डेटा पर अड़चनें हैं।
सुलह

जवाबों:


5

मैं select distinct onविंडो फ़ंक्शन के बजाय उपयोग करूंगा , फिर बस दिनों में शामिल हो जाएगा।

select 
    distinct on (date, client_id) date, 
    id 
from orders
inner join generate_series('2015-07-18'::date, '2015-07-19'::date, '1 day') date
  on start_date <= date and (end_date is null or date <= end_date)
order by date, client_id, order_type desc

http://sqlfiddle.com/#!15/5a420/16/0

अगर कुछ स्पष्ट नहीं है तो मैं अधिक विस्तार से बता सकता हूं।


यह अस्थायी आदेश / स्थायी आदेश को कवर नहीं करता है, लेकिन यह ज्वाइन होने के बाद किया जा सकता है =)
21

यह आपकी विंडो क्वेरी के समान क्रम निर्दिष्ट करता है। तो किसी भी (तिथि, ग्राहक_ के लिए) यह उल्टे अल्फबेटिक ऑर्डर में पहला ऑर्डर_टाइप का चयन करेगा।
साइमन पेरेपेलिट्स

आंतरिक जुड़ाव एकदम सही है, और विंडो की तुलना में चयन विशिष्ट समझना (और बस के रूप में अच्छी तरह से करता है) के लिए बहुत आसान है। किसी अन्य कारण से मुझे विंडोिंग फ़ंक्शंस का उपयोग नहीं करना चाहिए?
23

1
यह इसके बारे में। मुझे लगता distinct onहै कि विंडो क्वेरी की तुलना में और भी अधिक अनुकूलित है। वैसे, मुझे यह उल्लेख करना चाहिए कि यह एसक्यूएल में एक सामान्य "टॉप-इन-ग्रुप-ग्रुप" समस्या है: stackoverflow.com/questions/3800551/…
साइमन पेरपेलिट्स

यह एक महान पढ़ा है, मुझे कुछ अध्ययन करना है। यदि आपके पास कुछ समय है तो मेरे पास इस प्रश्न का एक विस्तारित संस्करण है जो यहां मैंने जो सीखा है उसका उपयोग करता है। dba.stackexchange.com/questions/108767/… मुझे यकीन है कि मैं इसे उस लिंक से जानने के लिए वापस अपडेट कर दूंगा। और धन्यवाद
reconbot

0

एक फ़ंक्शन लिखें जो किसी एकल दिनांक को पैरामीटर के रूप में लेता है और दिनांक + id की सूची लौटाता है जिसमें एक आदेश होता है।

फिर, जैसा कि आपने सुझाव दिया है जनरेट_सरीज का उपयोग करें और फ़ंक्शन को तिथि सीमा पर कॉल करें।

SQL में जटिल परिस्थितियों से निपटने के दौरान यह एक सामान्य रणनीति है।

मैंने नीचे कुछ कोड शामिल किए हैं, लेकिन ऊपर दिए गए SQL उत्तर बहुत सरल है।

यहाँ समारोह है:

create or replace function o( date) returns setof INT AS '
SELECT id from (
 SELECT
  id,
  first_value(id) OVER (PARTITION BY client_id ORDER BY order_type DESC) active_order_id
 FROM orders
 WHERE start_date <= $1 and (end_date is null OR end_date >= $1)
) active_orders
WHERE id = active_order_id;
' LANGUAGE sql ;

और इसे कैसे कॉल करें:

select distinct d, o(d::date) 
from generate_series('2015-07-18'::date, '2015-07-19'::date, '1 day') as d;

SQLFiddle


2
आप कुछ विवरण, नमूना कोड आदि के साथ उस उत्तर को फ्लश करना चाह सकते हैं। जैसा कि यह है, यह उत्तर नष्ट हो सकता है क्योंकि यह बहुत अस्पष्ट है।
मैक्स वर्नोन

क्या आप एक उदाहरण के साथ मेरी बेला को अपडेट कर पाएंगे? sqlfiddle.com/# -15
5a420/3/

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