Неожиданный результат при соединении таблицы за год - PullRequest
0 голосов
/ 08 ноября 2018

Я работаю с users, user_roles и point_standards. Пользователи должны достичь определенных баллов за определенный период, в зависимости от того, какую роль они выполняют. Очки извлекаются из курсов, которые проводятся в конкретном году. Получение пользовательских баллов - не проблема.

Для определенных баллов, которых должен достичь пользователь, определен критерий. Они сделаны в течение 3 лет и не могут перекрываться. См. Пример ниже.

enter image description here

Это означает, что с 2018 по 2020 год пользователю, которому назначена роль в соответствии с этими критериями, необходимо набрать 93 балла.

В 2018 году пользователь должен набрать 31 балл (93/3).

Проблема в том, что пользователь хочет проверить критерии по годам, соответствующие большему количеству критериев. Допустим, пользователь хочет проверить критерии в 2018, 2017 и 2016 годах. Это означает:

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

При потолке этих сумм это должно привести к критериям 65 баллов за 2018, 2017 и 2016 годы.

Для моего ожидаемого конечного результата я хочу получить обзор со всеми пользователями и критериями для конкретных лет.

В приведенном ниже примере я пытаюсь получить критерии для одного пользователя на 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 годов.

Затем я надеялся, что смогу суммировать points этих 3 строк для каждого пользователя.

Вопросы

  • Почему он возвращает только 2 строки вместо 3? Я выбрал 3 года, чтобы посмотреть.
  • Как я могу суммировать это количество строк вместе, чтобы я мог получить обзор всех пользователей?

1 Ответ

0 голосов
/ 08 ноября 2018

Вы не выбираете 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
...