网站三级分销数据库如何设计,简单案例

一、问题产生

有小伙伴微信私信我,说老板想设计一套三级返佣的微信淘宝客裂变系统,然后问我怎么搞…

咳咳,对于三级分销的数据库设计,相信很多小伙伴头疼的可能不是设计上,而是查询上,因为通常涉及到会员分级,那么涉及到的查询可能有且不局限于:一二级用户列表混合查询、统计今日注册一二级用户、统计本月注册一二级用户,如果涉及到了金额,那么可能还会有:查询一二级充值订单、查询一二级充值返佣金额等等等等。

首先我们来想一下,对于这种有上下级关系的表如何设计呢?

通常部门树是不是符合这个逻辑呢?我曹还别说,上下级部门表还真有那么点意思,我们来看一下这个表结构:

dept_iddemp_namedept_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_iduser_nameuser_parent_id
用户id用户名称父级用户id

用户关系表(user_relation):

iduser_parent_iduser_children_iduser_level
关系表主键父级用户id子级用户id用户等级

简单说明一下用户关系表的主键,设计上实际没什么作用,但是仍加上这个自增主键是因为,对于InnoDB存储引擎来说,如果当前表没有主键,那么会默认生成一个隐藏列作为自增主键,所以怎么都是生成主键,还不如自己指定一个主键,显式主键可以提高查询效率。(面试小技巧,Get到了吗)

通过如上两个表我们就可以很简单的区分上下级关系了,我们套入上边的数据看一下:

小明 > 小红 > 小王

小王 > 小刘 > 小张

iduser_parent_iduser_children_iduser_level
11(小明)2(小红)1(一级)
21(小明)3(小王)2(二级)
32(小红)3(小王)1(一级)
43(小王)4(小刘)1(一级)
53(小王)5(小张)2(二级)
64(小刘)5(小张)1(一级)

通过这种模式,是不是就清晰多了呢,感觉能分好多级啊,如果你想弄个四级分销,咳咳,亲,我这边建议您赶紧离职(国家规定超过三级就算违法)。

三、关系总结

最近有不少小伙伴微信私信我,关于这篇文章可能描述的并不清晰,所以临时补充一下节点三。

上边的表格数据实际只是到2级,并没有涉及3级,但是思路是一样的。

三级分销涉及到的其实是4个人,我们就以三级分销举个例子。

ABCD,A > B > C > D(箭头代表推广分销关系),D 消费后,C 拿一级代理返佣金额,B 拿二级代理返佣金额,A 拿三级返佣金额,如果 A 上面再有人,就不算了,因为这是三级营销,不然就成了四级营销。

有的小伙伴看到这,也觉得关系是捋顺了,但是代码不知道怎么写了?

其实这个关系表是在用户注册时产生的,且核心也是以新插入数据为基点,向上找

我们还是以 D 为例,D 注册后,会通过推荐码找到自己的上级 C,如果 C 再有上级那么就找到 B,B如果还有上级再找到 A,A 再往上就不找了,因为是三级分销。

其实落实到表中数据就是:

iduser_parent_iduser_children_iduser_level
1CD1(一级)
2BD2(二级)
3AD3(三级)

其实滤清这个关系,主要是以新增结点往上找,在代码中就很好体现了,比如 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(消费金额)
12(小红)5元
23(小王)3元
33(小王)4元

查询小明一二级用户订单返佣金额(假设一级用户返佣10%,二级用户返佣5%):

SELECTsum(decode(relation.user_level,1,orders.amount*0.1,2,orders.amount*0.05) ) AS rebate_amount
FROMuser_relation relation,user_orders orders
WHEREorders.USER_ID = relation.CHILDREN_USER_IDAND relation.user_parent_id = '1'and relation.user_level > 0

好了,到这罗列了几个一二级的简单查询,更多的查询大家自行根据场景需要编写。

博客园持续更新,欢迎大家订阅关注,一起成长。

本文首发于博客园:https://www.cnblogs.com/niceyoo/p/13614975.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/413932.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[js] 举例说明面向对象编程有什么缺点?

[js] 举例说明面向对象编程有什么缺点? 有实例化开销,内存消耗比较大,性能消耗比较大个人简介 我是歌谣,欢迎和大家一起交流前后端知识。放弃很容易, 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端…

第6课 仿Siri机器人-语音朗读和语音识别

一、功能设计输入文本,单击“朗读”按钮,由手机读出该文本(如果没有输入文本,则弹出消息框警告“请输入文本);单击“识别”按钮,读入语音,从文本框中输出文字。(另&#…

口述完SpringMVC执行流程,面试官就让同事回家等消息了

Srping MVC 执行流程真的是老生常谈的话题了,最近同事小刚出去面试,前面面试官相继问了几个 Spring 相关的问题,但当面试官问他,你知道 Srping MVC 的执行流程吗?小刚娴熟的巴拉巴拉回答完后,面试官就让他回…

[js] 使用js实现一个循环队列

[js] 使用js实现一个循环队列 const queue [] let queueRunning false let loopTimer null const loop task > {// do something...console.log(task)if (isQueueHasTask()) {// you can add new tasks in the middle of the queue.loopTimer setTimeout(() > {loo…

iview-cli 采坑记录

1.iview-cli 关于跨域的问题: 使用 webpack-devServer 启动 node 服务器可以通过配置 proxy 对象实现跨域: let proxyUrl http://dev.api.wankaonline.gm825.net;devServer: {proxy: {/index: {target: proxyUrl,pathRewrite: {^/index : /index},ws: t…

如何关闭线程池?会创建不会关闭?调用关闭方法时线程池里的线程如何反应?

前言 相信大家在面试的时候经常会遇到「线程池」相关的问题,比如: 什么是线程池?线程池的优点?有哪几种创建线程池的方式?四种创建线程池的使用场景?线程池的底层原理?线程池相关的参数&#…

[js] Number()的存储空间是多大?假如接口返回一个超过最大字节的数字怎么办?

[js] Number()的存储空间是多大?假如接口返回一个超过最大字节的数字怎么办? Number类型的最大值为2的53次方,即9007199254740992,如果超过这个值,比如900719925474099222,那么得到的值会不精确&#xff0…

C++ 判断系统大小字节序

bool IsLitterEndian() {union UTest{std::uint16_t t;std::uint8_t c;} endianTest{ 0x01 };return (endianTest.c 0x01); } 转载于:https://www.cnblogs.com/fluteary/p/9178627.html

macos brew zookeeper,安装后zookeeper启动失败?

一、Zookeeper安装流程 执行如下安装命令: brew install zookeeper执行截图如下: 安装后查看 zookeeper 安装信息(默认拉取最新版本) brew info zookeeper执行截图如下: 二、Zookeeper启动、状态查询、及关闭 启…

[js] alert如何让文本换行?

[js] alert如何让文本换行? 先考虑兼容性的问题,再使用转义字符 ie: alert("A\r\nB"); //chrome也可以实现 chrome: alert("A\nB");个人简介 我是歌谣,欢迎和大家一起交流前后端知识。放弃很容易…

批量更新数据(BatchUpdate)

批量更新数据&#xff08;BatchUpdate&#xff09; /// <summary> /// 批量更新数据&#xff0c;注意&#xff1a;如果有timestamp列&#xff0c;要移除 /// </summary> /// <param name"sourceTable">源数据</param> /// <param name&qu…

[js] 一个api接口从请求数据到请求结束共与服务器进行了几次交互?

[js] 一个api接口从请求数据到请求结束共与服务器进行了几次交互&#xff1f; API是一些预先定义的函数&#xff0c;或指软件系统不同组成部分衔接的约定。如果已经建立了连接&#xff0c;那么单次请求数据到请求结束应该是一次交互&#xff1b;如果没有建立连接&#xff0c;根…

为什么SimpleDateFormat不是线程安全的?

一、前言 日期的转换与格式化在项目中应该是比较常用的了&#xff0c;最近同事小刚出去面试实在是没想到被 SimpleDateFormat 给摆了一道… 面试官&#xff1a;项目中的日期转换怎么用的&#xff1f;SimpleDateFormat 用过吗&#xff1f;能说一下 SimpleDateFormat 线程安全问…

【Python 学习_第2周_程序代码】金角大王培训第二周练习_购物车代码,将写的代码和老师代码比较,记录下收获...

培训第二周&#xff0c;课堂练习为编写一段购物车代码&#xff0c;需求描述如下&#xff1a; 1.提示用户输入薪水 2.用户输入薪水后&#xff0c;打印商品编号、内容及价格 3.提醒用户输入商品代码&#xff0c;若余额大于等于商品价格&#xff0c;可购买&#xff1b;若小于&…

[js] js的循环结构有哪些?

[js] js的循环结构有哪些&#xff1f; for for in while do while个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

ActiveMQ Cannot send, channel has already failed: tcp:127.0.0.1:8161

仅针对如下错误内容&#xff1a; Cannot send, channel has already failed: tcp://127.0.0.1:8161一种尝试解决&#xff0c;修改连接端口为 61616&#xff1a; tcp://127.0.0.1:61616在没有修改过 ActiveMQ 配置文件情况下&#xff0c;默认 tcp 端口为 61616&#xff0c;htt…

[js] innerHTML有什么缺点?

[js] innerHTML有什么缺点&#xff1f; innerHTML的修改和添加&#xff0c;元素中旧的内容被移除新的内容会被重新写入元素。innerHTML内容将会被重新解析和构建元素。例如 innerHTML ”“ 时&#xff0c;内容”归零” 重写&#xff0c;所有的图片和资源重新加载&#xff0c;…

pip安装报错处理+PyPi源切换教程

一、pip安装出错类型 1.1 pip版本过旧导致不能安装 报错提示&#xff1a; You are using pip version 9.0.3, however version 10.0.1 is available. You should consider upgrading via the python -m pip install --upgrade pip comm and. 可通过以下命令升级pip python -m p…

面试官:说一下List排序方法

1. 前言 排序算是比较高频的面试题了&#xff0c;节前面试了的两家公司都有问到排序问题&#xff0c;整理后分享给大家&#xff08;文末见总结&#xff09;。 通常我们想到实现排序就是 Collections 工具类的 sort() 方法&#xff0c;而 sort() 方法有两种&#xff1a; 直接调…

[js] 举例说明js中什么是尾调用优化

[js] 举例说明js中什么是尾调用优化 写在前面 上次介绍了什么是尾调用以及怎么准确快速的判别一个函数调用是否为尾调用。那么&#xff0c;我们判别尾调用的意义是什么呢&#xff1f;做什么事情总归有个目的&#xff0c;那么今天我们就来系统的介绍一下尾调用的意义&#xff…