【问题标题】:Tree Traversal recursive calculation树遍历递归计算
【发布时间】:2012-07-16 20:34:43
【问题描述】:

我们有用户、问题和无限级别的类别。用户可以从问题中获得一些分数。问题可以有多个类别。

我想做的是计算每个类别的顶级用户:它只是从该类别下的问题中获得的总分,它也是子类别。

所以,我有这些表:

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

假设用户从 Zend Framework 获得 3 分,从 PHP 获得 2 分,从 java 获得 5 分1 分 来自 Rails。该用户每个类别的积分将是:

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

【问题讨论】:

    标签: php mysql algorithm tree


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      我将创建一个 user_categories 表,在其中存储 3 个值:user_idcategory_iduser_score。易于维护(只需INSERTUPDATE),也易于查询各个类别的顶级用户。

      【讨论】:

        【解决方案3】:

        如果您只想对每个顶级类别求和,那么您应该在您的类别表中添加一个名为 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
        

        【讨论】:

          【解决方案4】:

          这个 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...
          }
          

          【讨论】:

            猜你喜欢
            • 2018-07-12
            • 2014-03-11
            • 1970-01-01
            • 1970-01-01
            • 2020-08-15
            • 2017-05-11
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多