2017-04-19 9 views
5

में सबसे कम पथ कैसे प्राप्त करें मुझे उड़ान पर सभी स्टॉपओवर प्राप्त करने के लिए एक बयान प्राप्त करने में परेशानी है।फ्लाइट्रॉउट्स-टेबल

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

उदाहरण के लिए, मैं मार्गों

(18 > 24 | 24 > 87 | 87 > 1403) 

और नहीं

(18 > 24 | 24 > 87 | 87 > 99| 99 > 1403) 

यहाँ कुछ परीक्षण डाटा है प्राप्त करना चाहते हैं अगर मैं 18 से 1403 के लिए जाना चाहते

src_apid | dst_apid 
---------+---------- 
18  | 24 
24  | 87 
87  | 99 
87  | 1403 
99  | 18 
99  | 1403 

मेरी कोशिश इस तरह दिखती है:

WITH rejkabrest (
src_apid, 
dst_apid 
) AS (
SELECT 
    src_apid, 
    dst_apid 
FROM 
    routes 
WHERE 
    src_apid = 18 
UNION ALL 
SELECT 
    a.src_apid, 
    a.dst_apid 
FROM 
    routes a 
    INNER JOIN rejkabrest b ON a.src_apid = b.dst_apid 
    WHERE b.dst_apid = 1403 
) SELECT 
src_apid, dst_apid 
FROM 
rejkabrest; 

लेकिन इस तरह से मुझे केवल उन सभी मार्ग मिलते हैं जो स्रोत-हवाई अड्डे 18 से शुरू होते हैं। और यदि मैं एक और तरीका कोशिश करता हूं, तो मुझे लूप-समस्या मिलती है।

आशा है कि आप लोग मेरी मदद कर सकते हैं। अग्रिम में बहुत धन्यवाद!

+0

https://docs.oracle.com/cd/B19306_01/server.102/b14200/queries003.htm –

+0

[यह उत्तर] (http://stackoverflow.com/a/39119303/5089204) SQL-Server है वाक्यविन्यास, लेकिन आपको रास्ता बता सकता है। मुख्य चाल है, सभी विज़िट किए गए स्टेशनों के साथ बढ़ती स्ट्रिंग को ले जाने के लिए और यदि एक स्थान फिर से देखा जाता है तो रिकर्सन को रोकें। – Shnugo

उत्तर

3

उपयोग connect by nocycle और समारोह rank():

select path 
    from (
    select r.*, rank() over (order by lvl) rnk 
     from (select routes.*, level lvl, 
        sys_connect_by_path(src_apid, '->')||'->'||dst_apid path 
       from routes 
       connect by nocycle src_apid = prior dst_apid and src_apid <> 1403 
       start with src_apid = 18) r 
     where dst_apid = 1403) 
    where rnk = 1 

डेमो:

with routes (src_apid, dst_apid) as (
    select 18, 24 from dual union all 
    select 24, 87 from dual union all 
    select 87, 99 from dual union all 
    select 87, 1403 from dual union all 
    select 99, 18 from dual union all 
    select 99, 1403 from dual) 
select path 
    from (
    select r.*, rank() over (order by lvl) rnk 
     from (select routes.*, level lvl, 
        sys_connect_by_path(src_apid, '->')||'->'||dst_apid path 
       from routes 
       connect by nocycle src_apid = prior dst_apid and src_apid <> 1403 
       start with src_apid = 18) r 
     where dst_apid = 1403) 
    where rnk = 1 

PATH 
-------------------- 
->18->24->87->1403 
3

यहाँ एक तरह से पथ रिकर्सिवली निर्माण करना है। चक्र अपवादों से बचने के लिए CYCLE खंड का उपयोग करें। आपको ओरेकल के KEEP FIRST के साथ पाए गए पथों से सबसे छोटा रास्ता मिलता है।

with cte (dst_apid, path, stops) as 
(
    select dst_apid, src_apid || ' > ' || dst_apid as path, 0 as stops 
    from routes 
    where src_apid = 18 
    union all 
    select r.dst_apid, cte.path || ' > ' || r.dst_apid, cte.stops + 1 
    from cte 
    join routes r on r.src_apid = cte.dst_apid 
    where cte.dst_apid <> 1403 
) 
cycle dst_apid set cycle to 1 default 0 
select max(path) keep (dense_rank first order by stops) 
from cte 
where cte.dst_apid = 1403; 

KEEP FIRST के अलावा यह मानक एसक्यूएल है। इस मानक अनुपालन के लिए आप SELECT path FROM cte WHERE dst_apid = 1403 FETCH FIRST 1 ROW ONLY का उपयोग कर सकते हैं। ओरेकल इस वाक्यविन्यास का समर्थन 12 सी के रूप में करता है।

+0

हाय, आपके उत्तर के लिए धन्यवाद। आप भावी पाठकों के लिए लाइन 7 में cte.stops पर स्टॉप बदलना चाहेंगे (अन्यथा यह कम से कम मेरे लिए काम नहीं करेगा)। मैं वास्तव में क्वेरी निष्पादित करने में सक्षम नहीं था क्योंकि मेरी तालिका में हजारों पंक्तियां हैं। क्या प्रदर्शन बढ़ाने के लिए उड़ानों के बीच स्टॉप के लिए अधिकतम संख्या जोड़ना संभव होगा?30 मिनट के इंतजार के बाद मुझे अभी भी कोई परिणाम नहीं मिला: -/ – Steuerfahndung

+2

अच्छा, यह क्वालीफायर के बिना मेरे लिए काम करता है, लेकिन मैं इसे जोड़ दूंगा, क्योंकि यह स्पष्ट रूप से ओरेकल संस्करण पर निर्भर करता है (या आपके नाम पर एक कॉलम है मार्ग तालिका में बंद हो जाता है)। बेशक आप स्टॉप की संख्या को सीमित कर सकते हैं, उदाहरण: सीटी में जहां cte.dst_apid <> 1403 और cte.stops <4' कहां है। ('cte.stops <4' 4 स्टॉप तक सीमित है; आप जो भी नंबर चाहते हैं उसका उपयोग करें।) –

1

यदि आप प्रति उड़ान एक पंक्ति चाहते हैं, तो एकमात्र समाधान जो दिमाग में आता है वह दो पुनरावर्ती प्रश्न है। पहला नंबर 1, 1.1, 1.2, 1.1.1, आदि के साथ उड़ान मार्ग बनाता है; सेकंड एक ही मार्ग से संबंधित उड़ानें एकत्र करता है। बल्कि जटिल:

with cte1 (routepart, pos, src_apid, dst_apid) as 
(
    select to_char(rownum) as routepart, 1 as pos, src_apid, dst_apid 
    from routes 
    where src_apid = 18 
    union all 
    select cte1.routepart || '-' || rownum, pos + 1, r.src_apid, r.dst_apid 
    from cte1 
    join routes r on r.src_apid = cte1.dst_apid 
    where cte1.dst_apid <> 1403 
) 
cycle src_apid set cycle to 1 default 0 
, cte2 (route, routepart, pos, src_apid, dst_apid) as 
(
    select routepart as route, routepart, pos, src_apid, dst_apid 
    from cte1 
    where dst_apid = 1403 
    union all 
    select cte2.route, cte1.routepart, cte1.pos, cte1.src_apid, cte1.dst_apid 
    from cte1 
    join cte2 on cte2.routepart like cte1.routepart || '%' 
      and nvl(length(regexp_replace(cte2.routepart, '[[:digit:]]', '')), 0) = 
       nvl(length(regexp_replace(cte1.routepart, '[[:digit:]]', '')), 0) + 1 
) 
cycle src_apid set cycle to 1 default 0 
select pos, src_apid, dst_apid 
from 
(
    select 
    cte2.*, 
    rank() over (order by length(regexp_replace(route, '[[:digit:]]', ''))) as rn 
    from cte2 
) 
where rn = 1 
order by route, pos; 

उपयोग ROW_NUMBER बजाय RANK अगर आप संबंधों नहीं करना चाहती।