解决方案
从您的示例查询中,我能够简化您的表结构,它为我提供了足够的信息来回答您的问题。您可以使用此解决方案:
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
表的方式。
由于您想要子类别点的总和(按每个父类别)加上它们各自的父类别的点,我们可以通过垂直添加父类别UNION
并基本上使其成为其自身的子类别。然后,这将很好地纳入GROUP BY
and 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
没有 的情况下加入表UNION
,我们得到的连接看起来像(简化的列):
points_awarded ⋈ (links_from) category_relations ⋈ (links_to) points_awarded:
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
然后导致:
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
我们基本上将每个父类别都设为其自身的子类别。我们在我们的连接中使用这个结果,然后应该产生:
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
,我们现在可以对第一个进行分组category_id
,对第二个求和points_amount
(此时忽略第一个points_amount
,因为它无关紧要),为您提供所需的输出。