同表从属关系生成新的从属个数统计字段查询之join及mysql函数的应用

需求:

有一个会员表,会员员中以 from_uid 标识不同会员之间的主从关系。一个会员可以有多个子会员,一个子会员只有一个父级会员。现在按每个会员的子会员的个数多少来排序,同时输出每个会员的子会员个数。

解决:

这种方式可以用 join 来解决,一般情况下我们是多表之间的 join 联合统计查询操作。那么同表如何解决了,可以把这个表想像成两个不同的表,分别用不同的标识来模拟连接查询。在 TP 中可以这样写 sql 语句:

1
M('members')->alias('M')->join('__MEMBERS__ N on M.id=N.from_uid and N.status=1', 'LEFT')->field('M.*,IF( N.id IS NULL ,0,count(*)) as child_number')->where(array('M.status'=>1))->group('M.id')->order('child_number DESC,create_time DESC')->select();

会生成以下 sql 语句:

1
SELECT M.*,IF( N.id IS NULL,0,count(*))  as child_number FROM ape_members M LEFT JOIN ape_members N on M.id=N.from_uid and N.status=1  WHERE M.status = 1 GROUP BY M.id ORDER BY child_number DESC,create_time DESC

其中关键的有以下几个地方:
1、WHERE M.status = 1,这里的筛选条件一定是加上主表的标识才是正确的,不加 M 也是不对的。

2、GROUP BY M.id,如果不加这个的话,查询出来的结果只会显示有子会员的所有会员,没有子会员的会员是不会在结果集中的。

3、IF( N.id IS NULL,0,count()),这里不能直接写成 count(),因为如果这样写,得到的结果集中没有子会员的会员的 child_number 也为 1,count 空集也会返回 1。这里要加上 if 判断来使没有子会员的会员的子会员个数为 0 而不是 count 出来的 1.