一、問題產生
有小伙伴微信私信我,說老板想設計一套三級返佣的微信淘寶客裂變系統,然后問我怎么搞...
咳咳,對於三級分銷的數據庫設計,相信很多小伙伴頭疼的可能不是設計上,而是查詢上,因為通常涉及到會員分級,那么涉及到的查詢可能有且不局限於:一二級用戶列表混合查詢、統計今日注冊一二級用戶、統計本月注冊一二級用戶,如果涉及到了金額,那么可能還會有:查詢一二級充值訂單、查詢一二級充值返佣金額等等等等。
首先我們來想一下,對於這種有上下級關系的表如何設計呢?
通常部門樹是不是符合這個邏輯呢?我曹還別說,上下級部門表還真有那么點意思,我們來看一下這個表結構:
dept_id | demp_name | dept_parent_id |
---|---|---|
部門id | 部門名稱 | 父級(上級)部門id |
我們就按這個部門表的設計套進用戶表看看:
user_id(用戶id) | user_name(用戶名稱) | user_parent_id(父級用戶id) |
---|---|---|
1 | 小明 | 0(假設小明就是一級) |
2 | 小紅 | 1 |
3 | 小王 | 2 |
4 | 小劉 | 3 |
5 | 小張 | 4 |
現在的用戶數據等級關系為:( > 表示推薦)
小明 > 小紅 > 小王
小王 > 小劉 > 小張
如果我想查詢 小明
的二三級用戶,那么就需要通過sql語句:
select * from user where user.user_parent_id = '1' ...
不對不對,這樣查詢出來查到的是 小明
的二級用戶,想要查詢三級用戶的話,就需要用到子查詢了,那么對於這種情況在部門表是怎么解決的呢?
遞歸調用... 是的,遞歸調用,因為本身部門表的數據肯定是有限的,所以用這種方式查詢再加上緩存技術,這點查詢性能問題是完全可以忽略的了,但是用戶表如果這么設計就可以辭職回家了,怎么辦呢?
然后在接下來的討論過程中,小伙伴就說,怎么不給用戶表加一個等級標識呀,就是再加一個字段,比如 小紅
是 小明
的二級,那么這個這個字段就標記為2,小王
是 小明
的三級,那么就標記為3,這樣查詢不就好查詢了嗎。
還別說,聽上去感覺可以,但是,如上數據 小王
是 小明
的三級,但是 小王
同樣也是 小張
的一級,那么怎么標呢?
所以最終的問題就是,使用部門樹這種情況,區分或者查詢二三級用戶比較困難。
二、嘗試解決
其實后來小伙伴們提到的增加等級標識已經有那點意思了~
我們接下來將這個User表跟這個等級標識進行拆分一下:
用戶表(user):
user_id | user_name | user_parent_id |
---|---|---|
用戶id | 用戶名稱 | 父級用戶id |
用戶關系表(user_relation):
id | user_parent_id | user_children_id | user_level |
---|---|---|---|
關系表主鍵 | 父級用戶id | 子級用戶id | 用戶等級 |
簡單說明一下用戶關系表的主鍵,設計上實際沒什么作用,但是仍加上這個自增主鍵是因為,對於InnoDB存儲引擎來說,如果當前表沒有主鍵,那么會默認生成一個隱藏列作為自增主鍵,所以怎么都是生成主鍵,還不如自己指定一個主鍵,顯式主鍵可以提高查詢效率。(面試小技巧,Get到了嗎)
通過如上兩個表我們就可以很簡單的區分上下級關系了,我們套入上邊的數據看一下:
小明 > 小紅 > 小王
小王 > 小劉 > 小張
id | user_parent_id | user_children_id | user_level |
---|---|---|---|
1 | 1(小明) | 2(小紅) | 1(一級) |
2 | 1(小明) | 3(小王) | 2(二級) |
3 | 2(小紅) | 3(小王) | 1(一級) |
4 | 3(小王) | 4(小劉) | 1(一級) |
5 | 3(小王) | 5(小張) | 2(二級) |
6 | 4(小劉) | 5(小張) | 1(一級) |
通過這種模式,是不是就清晰多了呢,感覺能分好多級啊,如果你想弄個四級分銷,咳咳,親,我這邊建議您趕緊離職(國家規定超過三級就算違法)。
三、關系總結
最近有不少小伙伴微信私信我,關於這篇文章可能描述的並不清晰,所以臨時補充一下節點三。
上邊的表格數據實際只是到2級,並沒有涉及3級,但是思路是一樣的。
三級分銷涉及到的其實是4個人,我們就以三級分銷舉個例子。
ABCD,A > B > C > D(箭頭代表推廣分銷關系),D 消費后,C 拿一級代理返佣金額,B 拿二級代理返佣金額,A 拿三級返佣金額,如果 A 上面再有人,就不算了,因為這是三級營銷,不然就成了四級營銷。
有的小伙伴看到這,也覺得關系是捋順了,但是代碼不知道怎么寫了?
其實這個關系表是在用戶注冊時產生的,且核心也是以新插入數據為基點,向上找。
我們還是以 D 為例,D 注冊后,會通過推薦碼找到自己的上級 C,如果 C 再有上級那么就找到 B,B如果還有上級再找到 A,A 再往上就不找了,因為是三級分銷。
其實落實到表中數據就是:
id | user_parent_id | user_children_id | user_level |
---|---|---|---|
1 | C | D | 1(一級) |
2 | B | D | 2(二級) |
3 | A | D | 3(三級) |
其實濾清這個關系,主要是以新增結點往上找,在代碼中就很好體現了,比如 D 注冊時通過推薦碼找到C,然后 C 再通過用戶表的 parent_id 字段找到 B,依次類推找到 A,至於返佣的金額及規則就不闡述了,大家可以根據自己情況設置。
四、相關查詢
那么我們現在再來看看常用的數據查詢:
一級下級查詢:(小明的一級用戶為例)
select * from user_relation t where t.user_parent_id = '1' and user_level = '1'
二級用戶查詢:(小明的二級用戶查詢)
select * from user_relation t where t.user_parent_id = '1' and user_level = '2'
一二級用戶列表混合查詢:(小明的一二級用戶查詢)
select * from user_relation t where t.user_parent_id = '1'
對於當前用戶查詢時 user_id 肯定是明確的了,大家可以自行關聯 user 用戶表詳細信息
統計今日注冊的一級用戶:(小明的一級用戶為例)
select count(id) from user_relation relation where t.user_parent_id = '1' and user_level = '1' and relation.create_time = curdate()「mysql日期函數」
統計今日注冊的二級用戶:(小明的二級用戶為例)
select count(id) from user_relation relation where t.user_parent_id = '1' and user_level = '2' and relation.create_time = curdate()「mysql日期函數」
如果涉及到金額,或者訂單呢?
先上訂單表(精簡版):(user_orders)
order_id(訂單id) | user_id(用戶id) | amount(消費金額) |
---|---|---|
1 | 2(小紅) | 5元 |
2 | 3(小王) | 3元 |
3 | 3(小王) | 4元 |
... | ... | ... |
查詢小明一二級用戶訂單返佣金額(假設一級用戶返佣10%,二級用戶返佣5%):
SELECT
sum(
decode(relation.user_level,1,orders.amount*0.1,2,orders.amount*0.05)
) AS rebate_amount
FROM
user_relation relation,
user_orders orders
WHERE
orders.USER_ID = relation.CHILDREN_USER_ID
AND relation.user_parent_id = '1'
and relation.user_level > 0
好了,到這羅列了幾個一二級的簡單查詢,更多的查詢大家自行根據場景需要編寫。
博客園持續更新,歡迎大家關注,一起成長。