एक विभाजन में पहले गैर-शून्य मान को आगे बढ़ाने के लिए विंडो फ़ंक्शन का उपयोग करना


12

उस तालिका पर विचार करें जो रिकॉर्ड का दौरा करती है

create table visits (
  person varchar(10),
  ts timestamp, 
  somevalue varchar(10) 
)

इस उदाहरण डेटा पर विचार करें (काउंटर के रूप में सरलीकृत)

ts| person    |  somevalue
-------------------------
1 |  bob      |null
2 |  bob      |null
3 |  jim      |null
4 |  bob      |  A
5 |  bob      | null
6 |  bob      |  B
7 |  jim      |  X
8 |  jim      |  Y
9 |  jim      |  null

मैं उस व्यक्ति की सभी भविष्य की यात्राओं के अंतिम गैर-अशक्त व्यक्ति को तब तक आगे ले जाने की कोशिश कर रहा हूं, जब तक कि मूल्य में परिवर्तन नहीं हो जाता (यानी अगला गैर-शून्य) मान।

अपेक्षित परिणाम सेट इस तरह दिखता है:

ts|  person   | somevalue | carry-forward 
-----------------------------------------------
1 |  bob      |null       |   null
2 |  bob      |null       |   null
3 |  jim      |null       |   null
4 |  bob      |  A        |    A
5 |  bob      | null      |    A
6 |  bob      |  B        |    B
7 |  jim      |  X        |    X
8 |  jim      |  Y        |    Y
9 |  jim      |  null     |    Y

मेरा प्रयास इस तरह दिखता है:

 select *, 
  first_value(somevalue) over (partition by person order by (somevalue is null), ts rows between UNBOUNDED PRECEDING AND current row  ) as carry_forward

 from visits  
 order by ts

नोट: (कुछ-कुछ शून्य है) छँटाई के प्रयोजनों के लिए 1 या 0 का मूल्यांकन करता है ताकि मुझे विभाजन में पहला गैर-शून्य मान मिल सके।

उपरोक्त मुझे वह परिणाम नहीं देता जो मैं बाद में देता हूं।


क्या आप pg_dumppsql आउटपुट में डेटा चिपकाने के बजाय अपने टेस्ट डेटा के लिए पेस्ट कर सकते हैं , और टेबल के लिए स्कीमा? pg_dump -t table -d databaseहमें बनाने और COPYआदेशों की आवश्यकता है ।
इवान कैरोल


1
@a_horse_with_no_name जो उत्तर देने के योग्य है।
ypercube y

जवाबों:


12

निम्नलिखित क्वेरी वांछित परिणाम प्राप्त करती है:

select *, first_value(somevalue) over w as carryforward_somevalue
from (
  select *, sum(case when somevalue is null then 0 else 1 end) over (partition by person order by id ) as value_partition
  from test1

) as q
window w as (partition by person, value_partition order by id);

अशक्त स्थिति के बयान पर ध्यान दें - यदि IGNORE_NULL को विंडो कार्यों को पोस्टग्रेट्स द्वारा समर्थित किया गया था, तो इसकी आवश्यकता नहीं होगी (जैसा कि @ ypercubeᵀᴹ द्वारा उल्लेख किया गया है)


5
इसके अलावा सरलcount(somevalue) over (...)
ypercubeᵀᴹ

5

समस्या समस्याओं के अंतराल और द्वीपों की श्रेणी में है। यह एक अफ़सोस की बात है कि Postgres अभी तक IGNORE NULLविंडो फ़ंक्शन में लागू नहीं हुआ है FIRST_VALUE(), अन्यथा, यह आपकी क्वेरी में एक साधारण परिवर्तन के साथ, तुच्छ होगा।

विंडो कार्यों या पुनरावर्ती CTE के उपयोग से इसे हल करने के कई तरीके हैं।

सुनिश्चित नहीं है कि यह सबसे कुशल तरीका है लेकिन एक पुनरावर्ती CTE समस्या को हल करता है:

with recursive 
    cf as
    (
      ( select distinct on (person) 
            v.*, v.somevalue as carry_forward
        from visits as v
        order by person, ts
      ) 
      union all
        select 
            v.*, coalesce(v.somevalue, cf.carry_forward)
        from cf
          join lateral  
            ( select v.*
              from visits as v
              where v.person = cf.person
                and v.ts > cf.ts
              order by ts
              limit 1
            ) as v
            on true
    )
select cf.*
from cf 
order by ts ;

यह वास्तव में समस्या को हल करता है लेकिन इसके अधिक जटिल होने की आवश्यकता है। मेरा जवाब नीचे देखें
अधिकतम त्रिकोणीय

1
हाँ, आपका उत्तर अच्छा लग रहा है!
ypercube y
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.