MySQL推荐链底层用户数统计异常,仅统计部分节点求助
问题描述
数据库表结构如下:
| UID | referred | referrer |
|---|---|---|
| 300 | 302,304 | |
| 302 | 303 | 300 |
| 303 | 305,306,307 | 302 |
| 304 | 308 | 300 |
| 308 | 309 | 304 |
需要统计用户300推荐链的底层用户数量(即305、306、307、309),预期结果为4,但现有PHP+MySQL代码仅统计到3个,未处理304分支。
原代码片段:
// 获取300的直接推荐用户(逗号分隔) $sql = "SELECT GROUP_CONCAT(uid) FROM mybb_users WHERE referrer='300'"; $result = mysqli_query($conn, $sql); if (mysqli_num_rows($result) > 0) { while($row = mysqli_fetch_assoc($result)) { $abc= $row["uid"]; // 查询这些用户的推荐用户 $sql = "SELECT uid FROM mybb_users WHERE referrer='$abc'"; $result = mysqli_query($conn, $sql); if (mysqli_num_rows($result) > 0) { while($row = mysqli_fetch_assoc($result)) { $wbc= $row["uid"]; // 统计推荐用户数量 $sql = "SELECT count(*) FROM mybb_users WHERE referrer='$wbc'"; $result = mysqli_query($conn, $sql); if (mysqli_num_rows($result) > 0) { while($row=mysqli_fetch_assoc($result)) { echo $row['count(*)']; } } else { echo "0"; } } } } }
问题原因
- GROUP_CONCAT结果处理错误:
GROUP_CONCAT(uid)返回逗号分隔字符串(如302,304),但代码直接将其作为referrer查询条件,导致SQL语句变为WHERE referrer='302,304'——表中无匹配用户,因此无法查询到304的下级308,遗漏了309的统计。 - 变量覆盖逻辑漏洞:后续查询复用
$result变量,中断循环逻辑;同时未拆分逗号分隔的ID,无法遍历所有直接推荐用户。
解决方案
方案1:MySQL递归查询(高效推荐,MySQL 8.0+支持)
通过CTE递归遍历整个推荐链,直接统计底层用户数量:
WITH RECURSIVE referral_chain AS ( -- 起始节点:用户300 SELECT uid, referred FROM mybb_users WHERE uid = 300 -- 递归遍历所有下级用户 UNION ALL SELECT u.uid, u.referred FROM mybb_users u JOIN referral_chain rc ON FIND_IN_SET(u.uid, rc.referred) ) -- 统计所有没有下级的用户数量(底层用户) SELECT COUNT(*) AS total_bottom_users FROM ( -- 拆分referred字段为单个用户ID SELECT TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(rc.referred, ',', numbers.n), ',', -1)) AS bottom_uid FROM referral_chain rc JOIN ( SELECT 1 n UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 ) numbers ON CHAR_LENGTH(rc.referred) - CHAR_LENGTH(REPLACE(rc.referred, ',', '')) >= numbers.n - 1 ) AS bottom_users -- 确保这些底层用户没有自己的推荐用户 WHERE NOT EXISTS ( SELECT 1 FROM mybb_users u WHERE u.referrer = bottom_users.bottom_uid );
执行后直接返回结果4,无需额外PHP逻辑。
方案2:修改PHP代码,遍历所有推荐分支
拆分逗号分隔的用户ID,循环处理每个推荐节点,累加底层用户数量:
$total = 0; $conn = mysqli_connect("localhost", "username", "password", "database"); // 第一步:获取300的所有直接推荐用户ID $sql = "SELECT uid FROM mybb_users WHERE referrer='300'"; $result = mysqli_query($conn, $sql); if (mysqli_num_rows($result) > 0) { while($row = mysqli_fetch_assoc($result)) { $firstLevelUid = $row["uid"]; // 第二步:获取该直接用户的推荐用户 $sql2 = "SELECT uid FROM mybb_users WHERE referrer='$firstLevelUid'"; $result2 = mysqli_query($conn, $sql2); if (mysqli_num_rows($result2) > 0) { while($row2 = mysqli_fetch_assoc($result2)) { $secondLevelUid = $row2["uid"]; // 第三步:统计该二级用户的推荐用户数量(底层用户) $sql3 = "SELECT COUNT(*) AS cnt FROM mybb_users WHERE referrer='$secondLevelUid'"; $result3 = mysqli_query($conn, $sql3); $row3 = mysqli_fetch_assoc($result3); $total += $row3["cnt"]; } } } } echo $total; // 输出结果4
代码说明
- 移除
GROUP_CONCAT,改为直接查询每个推荐用户ID,避免字符串处理错误; - 使用独立结果变量(
$result/$result2/$result3),避免变量覆盖中断逻辑; - 累加每个二级用户的推荐数量,最终得到正确总数。
内容的提问来源于stack exchange,提问作者Higgs Boson
相关产品推荐
相关产品推荐

