计算类别和子类别的组合点

时间:2012-07-29 14:15:52

标签: mysql sum

我目前正在使用积分系统,该系统使用下面的查询列出一个类别或其下方任何类别中得分最多的人(使用'category_relations表'中的'links_to'和'links_from')。< / p>

SELECT  u.name, 
        pa.user_id, 
        SUM(IF(pa.plus = '1', pa.points_amount, 0)) - 
        SUM(IF(pa.plus = '0', pa.points_amount, 0)) AS points
FROM    points_awarded pa, Users u
WHERE   u.user_id = pa.user_id AND 
        (
           category_id = '" . $category_id . "' OR 
           category_id IN
               (
                   SELECT links_to
                   FROM category_relations
                   WHERE links_from = '" . $category . "'
               )
        ) 
GROUP BY user_id 
ORDER BY points DESC 
LIMIT 50

我现在要做的是切换此查询以查找特定用户的所有类别,而不是查找特定类别的所有用户。以下是我尝试使用的查询,但这只包括该类别的点,而不是下面的子类别。

SELECT   u.name, 
         pa.user_id, 
         pa.category_id,
         SUM(IF(pa.plus = '1', pa.points_amount, 0)) - 
         SUM(IF(pa.plus = '0',pa.points_amount, 0)) AS points
FROM     points_awarded pa, Users u
WHERE    u.user_id = pa.user_id AND 
         u.user_id = '" . $user_id . "'
GROUP BY pa.category_id 
ORDER BY points DESC 
LIMIT 50

2 个答案:

答案 0 :(得分:5)

解决方案

从您的示例查询中,我能够推导出表结构的简化,这为我提供了足够的信息来回答您的问题。您可以使用此解决方案:

SELECT   a.user_id, 
         a.name, 
         b.category_id,
         SUM(IF(d.plus = '1', d.points_amount, 0)) -
         SUM(IF(d.plus = '0', d.points_amount, 0)) AS points
FROM     Users a
JOIN     points_awarded b ON a.user_id = b.user_id
JOIN     (
         SELECT links_from, links_to 
         FROM   category_relations 
         UNION
         SELECT links_from, links_from
         FROM   category_relations 
         ) c ON b.category_id = c.links_from
JOIN     points_awarded d ON c.links_to = d.category_id
WHERE    a.user_id = $user_id
GROUP BY a.user_id,
         a.name,
         b.category_id
ORDER BY points DESC
LIMIT    50

其中$user_id是查询的用户ID参数。


击穿

基本上,此查询的关键组件是我们选择category_relations表的方式。

由于你想要子类别点的总和(按每个父类别) 加上 它们各自的父类别的点数,我们可以通过{{1}垂直增加父类别并且基本上使它成为自身的子类别。这将很好地考虑到UNIONGROUP BY

假设我们有一些(简化的)数据:

SUM

Users
------------------
user_id  |  name
433      |  Zane

points_awarded
------------------
user_id  |  category_id  |  plus  |  points_amount
433      |  1            |  1     |  785
433      |  2            |  1     |  871
433      |  3            |  1     |  236
433      |  4            |  0     |  64
433      |  5            |  0     |  12
433      |  7            |  1     |  897
433      |  8            |  1     |  3
433      |  9            |  0     |  48
433      |  10           |  1     |  124
433      |  14           |  0     |  676

为了区分父类和子类,查询使用category_relations ------------------ links_from | links_to 1 | 2 1 | 3 1 | 4 5 | 8 5 | 9 7 | 10 7 | 14 表中的两个字段在points_awarded表上进行自交叉引用连接。

如果我们刚刚加入category_relations表而没有category_relations,那么我们的结果将会像(简化列)一样:

points_awarded⋈(links_from)category_relations⋈(links_to)points_awarded:

UNION

如您所见,最左侧的category_id | points_amount | category_id | points_amount 1 | 785 | 2 | 871 1 | 785 | 3 | 236 1 | 785 | 4 | 64 5 | 12 | 8 | 3 5 | 12 | 9 | 48 7 | 897 | 10 | 124 7 | 897 | 14 | 676 是父类别,最右侧的category_id是相应的子类别。我们可以轻松地对第一个category_id和category_id第二个SUM ...

进行分组

但是等等,我们还需要包含父类别'points_amount!我们如何将第一个points_amount明显地放入第二个points_amount?这是points_amount发挥作用的地方。

在我们执行自我交叉引用连接之前,我们先选择UNION表,以便稍微改变它:

category_relations

然后导致:

SELECT links_from, links_to FROM category_relations
UNION
SELECT links_from, links_from FROM category_relations

我们基本上将每个父类别作为其自身的子类别。我们在连接中使用this的结果,然后产生:

category_relations (subselected)
------------------
links_from | links_to
1          | 1       <-- parent category
1          | 2
1          | 3
1          | 4
5          | 5       <-- parent category
5          | 8
5          | 9
7          | 7       <-- parent category
7          | 10
7          | 14

在那里, NOW 将父类别纳入category_id | points_amount | category_id | points_amount 1 | 785 | 1 | 785 1 | 785 | 2 | 871 1 | 785 | 3 | 236 1 | 785 | 4 | 64 5 | 12 | 5 | 12 5 | 12 | 8 | 3 5 | 12 | 9 | 48 7 | 897 | 7 | 897 7 | 897 | 10 | 124 7 | 897 | 14 | 676 ,我们现在可以对第一个SUM进行分组,对第二个进行汇总{ {1}}(此时忽略第一个category_id,因为它无关紧要),为您提供所需的输出。

答案 1 :(得分:2)

我很确定加入category_relations表有一种更简单的方法可以做到这一点,但很难看不到表格的任何可视化例子......我认为这应该有效:

SELECT   u.name
        ,pa.user_id
        ,pa.category_id,
        SUM(IF(pa.plus = '1', pa.points_amount, 0)) - SUM(IF(pa.plus = '0',pa.points_amount, 0)) AS points
FROM        points_awarded pa
JOIN        Users u
USING       (user_id)
WHERE       category_id IN(
    SELECT      links_to
    FROM        category_relations
    WHERE       links_from = (
        SELECT      category_id
        FROM        points_awarded
        WHERE       user_id = '" . $user_id . "'
    )
)       
GROUP BY    pa.category_id
ORDER BY    points DESC
LIMIT       50

您没有在上面发布的示例中看到子类别,因为您没有包含category_relations表中的记录。我们使用子子查询来查找与用户关联的所有category_ids,而不是通过查询的category_id查找链接的类别。给这一点,如果这不对,请发布一些显示表格数据的小片段。