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

Oracle में अंतराल और द्वीप समाधान - पुनरावर्ती का उपयोग

यह अंतराल और द्वीपों की समस्या का एक रूपांतर है, प्रत्येक द्वीप में पंक्तियों की अधिकतम संख्या की अतिरिक्त जटिलता के साथ। यह थोड़ा लंबा-चौड़ा है लेकिन आप अनुक्रम क्रम के कारण समूहों की पहचान करके शुरू कर सकते हैं:

select t.*,
  row_number() over (partition by "Description" order by "Start") as rn,
  case when lag("SequentialOrder")
    over (partition by "Description" order by "Start") < "SequentialOrder"
    then 1 else 0 end as newblock
from test t
order by "Start";

Start     Description MaximunRow SequentialOrder  RN   NEWBLOCK
--------- ----------- ---------- --------------- --- ----------
12-JUN-15 A                    3               3   1          0
13-JUN-15 A                    3               4   2          1
14-JUN-15 A                    3               5   3          1
01-JUL-15 A                    3               4   4          0
02-JUL-15 A                    3               3   5          0
04-JUL-15 A                    3               4   6          1
01-AUG-15 B                    2               5   1          0
16-AUG-15 B                    2               7   2          1

फिर आप एक पुनरावर्ती CTE का उपयोग कर सकते हैं (11gR2 से आगे) उसके आधार पर:

with u as (
  select t.*,
    row_number() over (partition by "Description" order by "Start") as rn,
    case when lag("SequentialOrder")
      over (partition by "Description" order by "Start") < "SequentialOrder"
      then 1 else 0 end as newblock
  from test t
),
r ("Start", "Description", "MaximunRow", "SequentialOrder", rn, blocknum,
  pos, lastmaxrow) as (
  select u."Start", u."Description", u."MaximunRow", u."SequentialOrder", u.rn,
    1, 1, u."MaximunRow"
  from u
  where rn = 1
  union all
  select u."Start", u."Description", u."MaximunRow", u."SequentialOrder", u.rn,
    case when r.pos = r.lastmaxrow or u.newblock = 0
      then r.blocknum + 1 else r.blocknum end,
    case when r.pos = r.lastmaxrow or u.newblock = 0
      then 1 else r.pos + 1 end,
    case when r.pos = r.lastmaxrow or u.newblock = 0
      then r.lastmaxrow else u."MaximunRow" end
  from r
  join u on u."Description" = r."Description" and u.rn = r.rn + 1
)
select * from r
order by "Start";

Start     Description MaximunRow SequentialOrder  RN   BLOCKNUM  POS LASTMAXROW
--------- ----------- ---------- --------------- --- ---------- ---- ----------
12-JUN-15 A                    3               3   1          1    1          3
13-JUN-15 A                    3               4   2          1    2          3
14-JUN-15 A                    3               5   3          1    3          3
01-JUL-15 A                    3               4   4          2    1          3
02-JUL-15 A                    3               3   5          3    1          3
04-JUL-15 A                    3               4   6          3    2          3
01-AUG-15 B                    2               5   1          1    1          2
16-AUG-15 B                    2               7   2          1    2          2

यह एक blocknum असाइन कर रहा है प्रत्येक पंक्ति में, एंकर सदस्य में प्रत्येक विवरण के लिए एक से शुरू होने के साथ, और पुनरावर्ती सदस्य में वृद्धि की जा रही है या तो newblock शून्य है (एक अनुक्रम विराम का संकेत) या ब्लॉक में सदस्यों की संख्या पिछली अधिकतम है। (मेरे पास 'पिछला अधिकतम' के लिए तर्क बिल्कुल सही नहीं हो सकता है क्योंकि यह प्रश्न में स्पष्ट नहीं है।)

फिर आप विवरण और उत्पन्न ब्लॉक संख्या के आधार पर समूह बना सकते हैं:

with u as (
  select t.*,
    row_number() over (partition by "Description" order by "Start") as rn,
    case when lag("SequentialOrder")
      over (partition by "Description" order by "Start") < "SequentialOrder"
      then 1 else 0 end as newblock
  from test t
),
r ("Start", "Description", "MaximunRow", "SequentialOrder", rn, blocknum,
  pos, lastmaxrow) as (
  select u."Start", u."Description", u."MaximunRow", u."SequentialOrder", u.rn,
    1, 1, u."MaximunRow"
  from u
  where rn = 1
  union all
  select u."Start", u."Description", u."MaximunRow", u."SequentialOrder", u.rn,
    case when r.pos = r.lastmaxrow or u.newblock = 0
      then r.blocknum + 1 else r.blocknum end,
    case when r.pos = r.lastmaxrow or u.newblock = 0
      then 1 else r.pos + 1 end,
    case when r.pos = r.lastmaxrow or u.newblock = 0
      then r.lastmaxrow else u."MaximunRow" end
  from r
  join u on u."Description" = r."Description" and u.rn = r.rn + 1
)
select min(r."Start") as "Start", max(r."Start") as "End", r."Description"
from r
group by r."Description", r.blocknum
order by r."Description", r.blocknum;

Start     End       Description
--------- --------- -----------
12-JUN-15 14-JUN-15 A          
01-JUL-15 01-JUL-15 A          
02-JUL-15 04-JUL-15 A          
01-AUG-15 16-AUG-15 B          

आपका नमूना डेटा अधिकतम पंक्तियों के विराम को ट्रिगर नहीं करता है क्योंकि आपके पास वैसे भी 3 से अधिक लंबा कोई क्रम नहीं है। कुछ अतिरिक्त डेटा के साथ:

Insert into TEST ("Start","Description","MaximunRow","SequentialOrder") values (to_date('15-JUN-15','DD-MON-RR'),'A',3,7);
Insert into TEST ("Start","Description","MaximunRow","SequentialOrder") values (to_date('16-JUN-15','DD-MON-RR'),'A',3,8);
Insert into TEST ("Start","Description","MaximunRow","SequentialOrder") values (to_date('17-JUN-15','DD-MON-RR'),'A',3,10);
Insert into TEST ("Start","Description","MaximunRow","SequentialOrder") values (to_date('18-JUN-15','DD-MON-RR'),'A',3,12);
Insert into TEST ("Start","Description","MaximunRow","SequentialOrder") values (to_date('19-JUN-15','DD-MON-RR'),'A',3,13);

वही क्वेरी मिलती है:

Start     End       Description
--------- --------- -----------
12-JUN-15 14-JUN-15 A          
15-JUN-15 17-JUN-15 A          
18-JUN-15 19-JUN-15 A          
01-JUL-15 01-JUL-15 A          
02-JUL-15 04-JUL-15 A          
01-AUG-15 16-AUG-15 B          

ताकि आप देख सकें कि यह क्रम परिवर्तन पर बंट रहा है और ब्लॉक में तीन पंक्तियों को हिट करने पर।

SQL Fiddle डेमो

आप newblock का उपयोग करने के बजाय सीधे केस स्टेटमेंट में अनुक्रमिक क्रम की तुलना करके, केवल पुनरावर्ती CTE से दूर हो सकते हैं, न कि पिछले मध्यवर्ती वाले से।; लेकिन rn . होना अगली पंक्ति को खोजने के लिए अगली तारीख खोजने की कोशिश करने से आसान है क्योंकि वे सन्निहित नहीं हैं।




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Oracle में किसी क्वेरी को कैसे दोहराएं

  2. N+1 अतिरेक और सर्वर समेकन

  3. ओरेकल पर एक स्थानिक सूचकांक बनाना

  4. मैं एक .NET अनुप्रयोग कैसे परिनियोजित कर सकता हूँ जो उपयोगकर्ता के लिए संपूर्ण घटक स्थापित किए बिना ODAC का उपयोग करता है?

  5. प्रज्ञा स्वायत्त_एक ट्रिगर में लेन-देन