确定“以下用户数””在多层成员数据库中
我为一个客户编写了一个会员网站,其中成员加入其他用户以下。例如
userid | name | subof
1 | John | 0
2 | Joe | 1
3 | Jill | 0
4 | Janet | 2
5 | Juan | 1
6 | George| 2
约翰和吉尔在顶部,乔和胡安在约翰之下,珍妮特和乔治在乔之下。分层用于放弃佣金。我的客户希望能够看到任何给定用户下方有多少用户(至少限制为8层)
现在我已将附加字段`num_below`添加到用户表中,并且只要有人加入或离开用户,该字段就会递增或递减。
这样做的第一个问题是,它感觉它违反了良好的数据库规范化实践〜因为它存储已经存在于数据库中的数据
第二个是,当我的客户来时,它会变得毛茸茸的说:“哦,乔治打算加入胡安,请移动他”
我考虑过每次要求时动态计算下面的数字,但数据库查询似乎会成倍增长。
我写了一个rectifySubs()
函数,可以通过并修复所有`num_below`字段,但是因为有更多的成员,它将变得越来越密集运行〜
function rectifySubs(){
$NumBelow=array();//UID=>NUM_BELOW
$SubOf=array();//UID=>IS_A_SUB_OF_UID
$Uids=array();//UID
$r=mysql_query("SELECT uid,subof FROM user");
if(!$r || mysql_num_rows($r)==0){return 'Invalid';}
while(list($uid,$subof)=mysql_fetch_row($r)){
$NumBelow[$uid]=0;
$SubOf[$uid]=$subof;
$Uids[]=$uid;
}
mysql_free_result($r);
$RungsUp=8;
foreach($Uids as $uid){
$r=1;
$parent=$SubOf[$uid];
while($parent>0 && $r<=$RungsUp){
$NumBelow[$parent]+=1;
$parent=$SubOf[$parent];
$r++;
}
}
$QueryByNum=array();
foreach($NumBelow as $uid=>$num){
if(!isset($QueryByNum[$num])){$QueryByNum[$num]=array();}
$QueryByNum[$num][]=$uid;
}
unset($QueryByNum[0]);
mysql_query("UPDATE user SET below=0");
foreach($QueryByNum as $num=>$uids){
$where=$or='';
foreach($uids as $uid){
$where.=$or."`uid`=".$uid;
$or=" OR ";
}
mysql_query("UPDATE user SET below=".$num." WHERE ".$where);
}
}
有什么建议?我不想在数据库中放置太多的冗余数据,但每次都会出现8层,这似乎太过于处理器。
- 编辑 -
我不清楚这些层是如何工作的,所以我把桌子做得更大了。我正在编辑的关键问题是,任何人都可以在其下方的层中拥有多个人。希望有道理。
- 解决方案 - (实施Kakao解决方案作为'会员'班级的方法)
protected function getNumBelowAtLevel($i=1,$force=false){
$i=abs((int)$i);
if($i<=1){return 0;}//Level 1 is just the member themselves
if($force || !isset($this->numBelow[$i])){
$Us='';
$Sels='';
$Lefts='';
$Groups='';
$comma='';
$nl='';
for($k=1;$k<=$i-1;$k++){
$j=$k==1?'0':$k-1;
$Us.=$comma.'u'.$k;
$Sels.=$comma.$nl.'m'.$k.'.mid as u'.$k;
$Lefts.=$nl.'left join members as m'.$k.' on m'.$k.'.subof = m'.$j.'.mid';
$Groups.=$comma.'u'.$k;
$nl="nttttt";
$comma=', ';
}
$sql="select count(*) - 1 as users_below
from (
select distinct {$Us}
from (
select
{$Sels}
from members as m0
{$Lefts}
where m0.mid = {$this->id}
group by {$Groups} with rollup
) d
) a";
if(DEBUG){var_dump($sql);}
$r=mysql_query($sql);
list($this->numBelow[$i])=mysql_fetch_row($r);
}
return $this->numBelow[$i];
}
没有找到相关结果
已邀请:
4 个回复
抚驰
更新 版本以下的多个成员:
蹦吃舷弦
,因为Joe本人不算作他自己的一部分。 编辑: 或者,看看: http://articles.sitepoint.com/article/hierarchical-data-database/2 这是一个不同的数据结构,更容易进行这种特殊的计算(子项数)和其他数据结构,但确实有自己的数字组(左/右)来维护。
皇小福另届
所以说你的老板要求乔下的人。 你想得到:珍妮特,黎明,詹姆斯,道格 - 对吗? 如何更改subof的定义(在我的示例中,我已将其设为varchar),而不是添加新列? 所以你的桌子会这样:
金字塔的顶部是0,所以约翰和吉尔仍然在顶部。然后你知道0下面的序列是谁。 将john和jill更改为0而不是0.0以使更新更容易 这样做可以在以下查询中获得所需的结果:
所以你的下一个问题是如何插入一个新的新兵。好。比尔来自道格。那么比尔的插入是什么? //首先获取subof和userid
//然后插入新行,即subof.userid
所以现在你有另一行:
但是等等......还有更多! 用詹姆斯和道格取代了乔治和胡安的新桌子,专注于修改过的问题: =====乔治和胡安的新例子
约翰和吉尔位居榜首,乔和 胡安在约翰,珍妮特和 乔治在乔面前。分层是 用于放弃佣金。 题 我的 客户希望能够看到如何 许多用户低于任何给定用户, (至少它限制在8层 出) 回答
题 它变得多毛了 我的客户来了,说:“哦,乔治 我想加入胡安,请搬家 他” 回答 SELECT userid,name,subof FROM tablename 在哪里的名字('胡安','乔治');
所以你的自动查询看起来像这样:
给你这个新结果:
请享用! 黎明
脖呐
希望你觉得它有用 - 下面的完整脚本:) 完整脚本: