在一年范围内加入表格时出现意外结果

时间:2018-11-08 10:18:49

标签: mysql join group-by

我正在使用usersuser_rolespoint_standards。用户需要根据自己的角色在一定时期内达到一定的目标。从特定年份完成的课程中获取积分。检索用户点不是问题。

对于用户必须达到的某些点,定义了一个标准。这些都是3年,不能重叠。请参见下面的示例。

enter image description here

这意味着,从2018年到2020年,具有分配给这些条件的角色的用户需要达到93分。

2018年,用户应获得31分(93/3)。

问题是当用户想要检查与更多条件相对应的年份的条件时。假设用户要检查2018、2017和2016年的条件。这意味着:

(93 / 3) + (50 / 3) + (50 / 3) 

以这些总和为上限时,这将导致2018年,2017年和2016年的标准为65分。

对于我的最终预期结果,我希望获得所有用户的概述以及特定年份的标准。

在下面的示例中,我试图检索单个用户在2018、2017和2016年的条件。

SELECT `users`.first_name,
        ps.points

FROM `users`
       # Join the user roles table
       INNER JOIN `user_roles`
         ON `users`.`role_id` = `user_roles`.`id`

       # Get the criteria for 2018, 2017 and 2016
       LEFT JOIN (SELECT id, role_id, COALESCE(points / 3) AS points
                  FROM point_standards
                  WHERE 2018 BETWEEN YEAR(start_year) AND YEAR(end_year)
                     OR 2017 BETWEEN YEAR(start_year) AND YEAR(end_year)
                     OR 2016 BETWEEN YEAR(start_year) AND YEAR(end_year)) ps
         ON (user_roles.id = ps.role_id)

WHERE users.id = 123
GROUP BY `users`.`id`, ps.id
ORDER BY `points_internal` DESC

这将导致2行具有正确的条件。

enter image description here

预期结果

在这种情况下,它应该返回3行。这是因为我想查看2018、2017和2016年的标准。

然后我希望可以为每个用户对这3行中的points求和。

问题

  • 为什么只返回2行而不是3行?我已经选择3年了。
  • 如何将这些行的数量总计在一起,以便获得所有用户的概览?

1 个答案:

答案 0 :(得分:1)

您没有选择3行,而是选择了至少包含2016、2017、2018年其中之一的所有行,而这些行中恰好有两行(表中的前两行)。

如果要为这三种情况中的每种情况分别使用行,则可以为每种情况编写一个子查询,并对它们执行UNION ALL。所以不用写

SELECT id, role_id, COALESCE(points / 3) AS points
FROM point_standards
WHERE 2018 BETWEEN YEAR(start_year) AND YEAR(end_year)
    OR 2017 BETWEEN YEAR(start_year) AND YEAR(end_year)
    OR 2016 BETWEEN YEAR(start_year) AND YEAR(end_year)

您使用

SELECT id, role_id, COALESCE(points / 3) AS points
FROM point_standards
WHERE 2018 BETWEEN YEAR(start_year) AND YEAR(end_year)
UNION ALL
SELECT id, role_id, COALESCE(points / 3) AS points
FROM point_standards
WHERE 2017 BETWEEN YEAR(start_year) AND YEAR(end_year)
UNION ALL
SELECT id, role_id, COALESCE(points / 3) AS points
FROM point_standards
WHERE 2016 BETWEEN YEAR(start_year) AND YEAR(end_year)

如果您有一个从中获取年份的表,则可以与此表执行联接,这比较省事。

编辑:整个查询应如下所示:

SELECT `users`.first_name,
        ps.points

FROM `users`
    # Join the user roles table
    INNER JOIN `user_roles`
        ON `users`.`role_id` = `user_roles`.`id`

    # Get the criteria for 2018, 2017 and 2016
    LEFT JOIN (
            SELECT id, role_id, COALESCE(points / 3) AS points
            FROM point_standards
            WHERE 2018 BETWEEN YEAR(start_year) AND YEAR(end_year)
            UNION ALL
            SELECT id, role_id, COALESCE(points / 3) AS points
            FROM point_standards
            WHERE 2017 BETWEEN YEAR(start_year) AND YEAR(end_year)
            UNION ALL
            SELECT id, role_id, COALESCE(points / 3) AS points
            FROM point_standards
            WHERE 2016 BETWEEN YEAR(start_year) AND YEAR(end_year)
            ) ps
        ON (user_roles.id = ps.role_id)

WHERE users.id = 123
GROUP BY `users`.`id`, ps.id
ORDER BY `points_internal` DESC

或更短一点(通过创建自己的years子查询):

SELECT `users`.first_name,
        ps.points

FROM `users`
    # Join the user roles table
    INNER JOIN `user_roles`
        ON `users`.`role_id` = `user_roles`.`id`

    # Get the criteria for 2018, 2017 and 2016
    LEFT JOIN (
            SELECT id, role_id, COALESCE(points / 3) AS points
            FROM point_standards
            JOIN (SELECT 2016 AS y UNION SELECT 2017 AS y UNION SELECT 2018 AS y) years
            ON years.y BETWEEN YEAR(start_year) AND YEAR(end_year)
            ) ps
        ON (user_roles.id = ps.role_id)

WHERE users.id = 123
GROUP BY `users`.`id`, ps.id
ORDER BY `points_internal` DESC