2012-07-16 148 views
0

我们有用户,问题和无限级别的类别。用户可以从问题中获得一些观点。问题可以有多个类别。树遍历递归计算

我想要做的是计算每个类别的最高用户数:它只是从该类别下的问题中获得的总点数,也是它的子类别。

所以,我有这些表:

questions 
-------------- 
id 
title 
question 

categories 
-------------- 
id 
parent_id 
category 
lft 
rgt 

question_categories 
-------------- 
question_id 
category_id 

users 
-------------- 
id 
username 

user_points 
-------------- 
id 
user_id 
question_id 
point_type 
points 

user_category 
-------------- 
user_id 
category_id 
points  

我想要做的是计算user_category.points值。 总结每个类别的要点很简单,但包括子类别越来越复杂。

什么可能是最好的方法来做到这一点?

计算的例子:

假设的类别是:

Programming 
    PHP 
     Zend Framework 
     Symfony 
    Java 
    Ruby on Rails 

假设用户得到3分从Zend框架,2点从PHP,5分从Java和来自Rails的1分。每类此用户的积分将是:

Programming   11 (5+5+1) 
    PHP     5 (2+3) 
     Zend Framework 3 
     Symfony 
    Java     5 
    Ruby on Rails  1 

回答

0

我会创造一个user_categories表,其中我将存储3个值:user_idcategory_iduser_score。它很容易维护(只需要INSERTUPDATE),并且它也很容易查询每个类别的最高用户。

1

也许最好是使用标签而不是层次结构。例如,任何带有“Zend Framework”的东西都会有“PHP”和“Programming”标签。这也有助于某些类别可以出现在多个地方。例如,我可以在jQuery和Javascript中使用ajax。然后,为该用户的类别中列出的每个标签添加1。

0

如果您只计算每个顶级类别的总和,那么您应该在名为root_id的类别表中添加一个字段(保存该类别的传递父级的ID)。

那么你的总和将被计算为:

select up.user_id, ctg.root_id, sum(up.points) 
from user_points up 
join question_categories qc on up.question_id = qc.question_id 
join categories ctg on qc.category_id = ctg.id 
group by up.user_id, ctg.root_id 
0

这个PHP和SQL应该让你的前3名用户为每个类别包括子类:

$query = "SELECT id, parent_id FROM categories"; 
$parent = array(); 
...fetch mysql data loop depending on what connection you use, mysqli or pdo... 
{ 
    $parent[$result['id']] = $result['parent_id']; 
} 

$childs = array(); 

foreach($parent as $id => $parrent_id) 
{ 
    $childs[$parrent_id][$id] = $id; 
    $next_parrent_id = $parrent_id; 
    while($next_parrent_id = $parent[$next_parrent_id]) 
    { 
     $childs[$next_parrent_id][$id] = $id; 
    } 
} 

foreach($parent as $id => $parrent_id) 
{ 
    $current_categories = array($id => $id) + $childs[$id]; 
    $query = "SELECT user_id, username, SUM(points) AS total_points 
      FROM user_points 
      LEFT JOIN users ON (user_id = users.id) 
      LEFT JOIN question_categories USING (question_id) 
      WHERE category_id IN (" . implode(', ', $current_categories). ") 
      ORDER BY total_points DESC 
      LIMIT 3"; 
    ...fetch mysql data loop... 
}