鍍金池/ 問答/人工智能  數(shù)據(jù)庫/ mysql左右值樹怎樣計(jì)算某層節(jié)點(diǎn)數(shù)據(jù)?

mysql左右值樹怎樣計(jì)算某層節(jié)點(diǎn)數(shù)據(jù)?

公司是做直銷系統(tǒng)的,因?yàn)闃I(yè)務(wù)需要,給客戶做一個(gè)雙軌會(huì)員制系統(tǒng)設(shè)計(jì)。里面會(huì)員關(guān)系用到了左右值數(shù)計(jì)算。

雙軌就是,每個(gè)節(jié)點(diǎn)只允許最多有兩個(gè)直接子節(jié)點(diǎn)。

左區(qū),就是某個(gè)節(jié)點(diǎn)下面左邊的節(jié)點(diǎn)列表
右區(qū),就是某個(gè)節(jié)點(diǎn)下面右邊的節(jié)點(diǎn)列表

要結(jié)算對碰獎(jiǎng)金,我現(xiàn)在需要計(jì)算出以某層為根節(jié)點(diǎn),能夠獲得第N層的左區(qū)或者右區(qū)節(jié)點(diǎn)數(shù)據(jù)
我的表結(jié)構(gòu)數(shù)據(jù)是這樣的,

圖片描述

表名:kt_relation
relation_id :沒啥用,一般沒用他
user_id :這是會(huì)員id,我用他來記錄某個(gè)節(jié)點(diǎn)左右區(qū)是否已經(jīng)占用。
Lft:左值
Rgt:右值
Lft_sub:某會(huì)員id左區(qū)是哪個(gè)會(huì)員,沒有就是0,
Rgt_sub:某會(huì)員id右區(qū)是哪個(gè)會(huì)員,沒有就是0.
Level:層數(shù),跟節(jié)點(diǎn)是第一層。也就是所在樹中的深度。

我算出來了,以跟節(jié)點(diǎn)為準(zhǔn)10001,第N層的左右區(qū)節(jié)點(diǎn)列表,sql語句是這樣的。

Child.user_id, Child.Lft, Child.Rgt,Child.Level
            FROM kt_relation as Child, kt_relation as Parent
                WHERE
                  Child.Level = 3
                  AND Child.Lft+Child.Rgt <= Parent.Lft +Parent.Rgt
                  AND Parent.user_id = 10001

核心就是:Lft+Rgt<=Lft+Rgt,某個(gè)父親子節(jié)點(diǎn)左右值之和<=父親節(jié)點(diǎn)的左右值之和,那么他就是父親節(jié)點(diǎn)的左區(qū),然后我想查看第3層,看看有哪些節(jié)點(diǎn)。

組織架構(gòu)圖

現(xiàn)在我想查詢,如上圖黃色的user_id是10003的,這個(gè)節(jié)點(diǎn),他的左區(qū)的第三層是哪些節(jié)點(diǎn),應(yīng)該是綠色那兩個(gè)節(jié)點(diǎn)。現(xiàn)在就是卡到這里,弄不動(dòng)了。

我自己的想法是,還是用上面那種sql從根節(jié)點(diǎn)開始,10003的第三層應(yīng)該是10001的第4層,10003在10001的右區(qū),那么我就把10001的左區(qū)都排除,只查詢10001第4層的右區(qū)有多少節(jié)點(diǎn),顯然把10013也包含進(jìn)去了。這個(gè)又堵住了,感覺行不通。即便可行,也存在一個(gè)問題。就是要好多條sql語句,才能完成最終結(jié)果。有沒有辦法,只用像上面那種一條就出結(jié)果的,查詢耗時(shí)在0.035s,0.02s這種的語句。

因?yàn)椴幌朐谶@里太耗時(shí),后面還有很多計(jì)算獎(jiǎng)金的查詢,更新什么的,又要耗時(shí)間。盡可能查詢時(shí)間短點(diǎn)。我都做了索引了。

不知道我說清楚沒有,有大俠對左右值算法有研究的朋友,指點(diǎn)指點(diǎn)。

回答
編輯回答
不將就
SELECT Child.user_id, Child.Lft, Child.Rgt,Child.Level
            FROM kt_relation as Child, kt_relation as Parent
                WHERE
                  Child.Level = 3+1
                  -- AND Child.Lft+Child.Rgt <= Parent.Lft +Parent.Rgt   -- 左區(qū)
                                    
                                    AND Child.Lft+Child.Rgt > Parent.Lft +Parent.Rgt    -- 右區(qū)
                  
                                    AND Parent.user_id = 10001
                                    
                                    AND Child.Lft+Child.Rgt <= 12 +25

搞出來了一個(gè)sql語句,可以實(shí)現(xiàn)。前提是確認(rèn)這個(gè)節(jié)點(diǎn)是最頂層節(jié)點(diǎn)10001的哪個(gè)區(qū)域,然后查10001的右區(qū),再加個(gè)條件,查詢10003的左區(qū),12+25就能代表10003了。
這種自連接,搞的我有點(diǎn)暈乎!速度還可以,可能是有索引的原因。
php里面就是,先取得待查的節(jié)點(diǎn)10003的記錄,取出他的,左右值。
然后計(jì)算出,應(yīng)該查以根節(jié)點(diǎn)開始的哪層。比如這個(gè)10003,要查他開始的第3層,那實(shí)際查的應(yīng)該是,10001的第4層。因?yàn)?0003與10001差1層。所以是,3+1層。什么亂七八糟的。

搞出來個(gè)簡單的,先查出這個(gè)節(jié)點(diǎn)的所有子孫節(jié)點(diǎn),加條件,和值小于自身,再限定定層。就出來了。
SELECT * FROM Tree WHERE Lft > 1 AND Lft < 26 AND Lft + Rgt <= 1 + 26 AND Level = 4

為什么,我把問題寫出來,然后不久,自己就解決了問題,好怪。不寫就整不出來。其實(shí)我就是個(gè)菜b

2017年6月26日 06:56