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

joh*_*ohn 6 mysql sum

我目前正在使用点系统,该系统使用下面的查询列出一个类别中的点数最多的人或其下方的任何类别(使用'category_relations表'中的'links_to'和'links_from').

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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

Zan*_*ien 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
Run Code Online (Sandbox Code Playgroud)

$user_id查询的用户ID参数在哪里.


分解

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

由于您需要子类别点的总和(按每个父类别)加上它们各自的父类别的点,我们可以垂直地通过父类别来处理UNION它,并且基本上使它成为自身的子类别.这将很好地考虑到GROUP BYSUM.

假设我们有一些(简化的)数据,如下所示:

Users
------------------
user_id  |  name
433      |  Zane
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
category_relations
------------------
links_from | links_to
1          | 2
1          | 3
1          | 4
5          | 8
5          | 9
7          | 10
7          | 14
Run Code Online (Sandbox Code Playgroud)

为了区分父类和子类,查询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
Run Code Online (Sandbox Code Playgroud)

如您所见,最左边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
Run Code Online (Sandbox Code Playgroud)

然后导致:

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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

在那里,现在将父类别考虑在内SUM,我们现在可以对第一个category_id进行分组,对第二个进行求和points_amount(忽略第一个points_amount,因为它是不相关的),为您提供所需的输出.

  • @john,这就是为什么我们需要查看您的表架构和示例数据,以便我们能够为您的问题制定准确的解决方案; 否则我们只是盲目地发射,希望它是你需要的.您是否在`points_awarded`表中多次存储`user_id - > category_id`的组合?(在这种情况下,这将需要一个中间的"GROUP BY"和"SUM").什么是`plus`字段?类别层次结构是否超过一个级别? (2认同)

Web*_*ist 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
Run Code Online (Sandbox Code Playgroud)

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