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