Discuz环境PHP生成随机排名写入t2_rank出现数据重复排查
问题分析
你的代码存在以下5个核心问题,直接导致数据重复写入、批次缺失:
- foreach循环变量引用错误:遍历
t1_user结果集时你使用了未定义的$id变量,没有读取当前行的用户ID$su['id']。如果运行环境存在全局$id变量刚好从1递增到1000后重置,就会出现前1000条ID正常、后续从头重复的现象。 array_slice参数使用错误:array_slice第三个参数是截取长度不是结束下标,你每次循环累加$tpp导致截取长度越来越大,会出现重复截取、批次数据错乱的问题,正确长度应该固定为500。- 循环边界错误:总批次
$runningtime计算完成后,你用$y < $runningtime作为循环条件,会少执行最后一批写入:比如5400条数据需要11批次,你的代码只会执行10次,漏掉最后400条。 - 数组下标不匹配:你给
$newdata赋值时下标从1开始,而array_slice默认按0起始的偏移量计算,容易出现数据错位问题。 - SQL插入字段缺失:
t2_rank表存在name字段,但你的REPLACE INTO语句只插入了rank和id两个字段,如果name字段没有设置外键自动同步或默认值,也会导致字段数据异常。
修复后代码
$checkfirst = DB::result_first("SELECT count(*) cnt FROM ".DB::table('t2_rank')); if($checkfirst == 0){ // 仅读取需要的字段减少内存占用 $s = DB::fetch_all("SELECT id,name FROM ".DB::table('t1_user')." ORDER BY RAND()"); $newdata = []; $total = count($s); foreach($s as $k => $su){ $rank = $k + 1; // 字符串转义避免SQL注入 $name = addslashes($su['name']); $newdata[] = "($rank, {$su['id']}, '$name')"; } $pagesplit = 500; // 每批写入500条 $runningtime = ceil($total / $pagesplit); for($y=0; $y < $runningtime; $y++){ $offset = $y * $pagesplit; // 固定截取长度为500,不足时自动取到数组末尾 $genewdata = array_slice($newdata, $offset, $pagesplit); $tobeupdate = implode(',', $genewdata); DB::query("REPLACE INTO ".DB::table('t2_rank')." (rank,id,name) VALUES ".$tobeupdate); } }
如果你
t2_rank的name字段已经通过外键关联t1_user自动同步,可以省略插入name字段,对应调整SQL的字段和值部分即可。
内容的提问来源于stack exchange,提问作者Swee Hong
相关产品推荐
相关产品推荐

