? ? 在code的過程中曾經(jīng)遇到過一個神奇的問題:
? ? 現(xiàn)在有多條火車線路,經(jīng)過了若干站點,找出經(jīng)過P站點能直接到達的所有站點。
? ? 其中在數(shù)據(jù)庫中存儲的線路是分路段存儲,格式是? ID? ?A_STATION? Z_STATION? 其他屬性略,比如? ? ?a->b->c->d->e->f->g 那么存儲的數(shù)據(jù) 為??
? ? ? ? 1? ?a? ? b
? ? ? ? 2? ?c? ? b
? ? ? ? 3? ? c? ? d
? ? ? ? ...
? ? 看出來了,分路段存儲,但是又無序,不是嚴格按照? a->b , b->c , c->d 這樣存儲的,剛開始的時候,我也沒有想過其他方法,直接在代碼中使用了遞歸來判斷,循環(huán)查詢數(shù)據(jù),但是發(fā)現(xiàn)這樣效率并不高,而且遞歸的過程中很容易出錯,這時候,我發(fā)現(xiàn)oracle中有一個connect by實現(xiàn)的遞歸查詢,于是打算使用一下。
? ? 使用過程中發(fā)現(xiàn)由于數(shù)據(jù)不是嚴格的有序排序,A,Z無序,無法直接使用,這時,我動了一個歪腦筋,由于表中數(shù)據(jù)量也不是太大,只有幾萬條記錄,我能不能把表中所有數(shù)據(jù)翻轉(zhuǎn)一下,A,Z 變成 Z,A然后重命名為 A,Z,再使用union 拼接成兩倍記錄的新表,想到之后馬上就做,于是有了:
? ?? (select id,a_id,z_id
? ? ? ? ? ?from table
? ? ? ? ? ? ?union
? ? ? ? ? ? select id,z_id as a_id,a_id as z_id
? ? ? ? ? ?from table) t
? ? 這是一張新的表,里面的記錄是原表的兩倍,然后對這個表進行connect by 遞歸查詢:
? ??????select *
? from (select id, a_id, z_id
? ? ? ? ? from table
? ? ? ? union
? ? ? ? select id, z_id as a_id, a_id as z_id
? ? ? ? ? from table) t
start with t.a_id = ?
connect by? prior t.z_id = t.a_id
? ? 哈哈,這下好了吧,解決了無序的問題??墒切碌膯栴}出現(xiàn)了,我一運行,沒有報錯,可是數(shù)據(jù)怎么有問題。重復(fù)了兩次?仔細一想,數(shù)據(jù)重復(fù)了兩次,這樣不但查詢出來的結(jié)果會有問題,而且說不定還會報無限遞歸調(diào)用的錯誤(可能是我使用的ID正好,所有偶然的沒有報錯,不然會無限遞歸報錯)。這個怎么解決呢?
? ? 然后我查詢了一下網(wǎng)上oracle 的 connect by 使用的很多案例,發(fā)現(xiàn)了oracle的一個關(guān)鍵字“NOCYCLE”,還有嵌套使用的一個條件“connect_by_iscycle = 0”,限制了遞歸過程中不能成環(huán),然后再加上我自己生成的數(shù)據(jù)跟原始數(shù)據(jù)的id是相同的,那么我可以限制id只能出現(xiàn)一次,不能重復(fù)使用一條記錄遞歸“t.id <> t.id”經(jīng)過修改,最終的SQL成了下面這樣:
select *
? from (select id, a_id, z_id
? ? ? ? ? from table
? ? ? ? union
? ? ? ? select id, z_id as a_id, a_id as z_id
? ? ? ? ? from table) t
where connect_by_iscycle = 0
start with t.a_id = ?
connect by NOCYCLE prior t.z_id = t.a_id
? ? ? and prior t.id <> t.id
? ? 最終實現(xiàn)了需求,當然,我這樣使用在很多時候是不合規(guī)的,有什么不對的,還請大家指出,只是這里是一種特殊的情況中的特殊用法,這種騷操作還是不要推廣的好。