Хобрук: Ваш путь к мастерству в программировании

Неожиданный результат при присоединении к таблице в диапазоне лет

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

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

введите здесь описание изображения

Это означает, что с 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 строкам с правильными критериями.

введите здесь описание изображения

Ожидаемый результат

В этом случае он должен вернуть 3 строки. Это потому, что я хочу увидеть критерии 2018, 2017 и 2016 годов.

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

Вопросы

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

Ответы:


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
08.11.2018
  • Нужен ли мне тогда другой LEFT JOIN для каждого случая? 08.11.2018
  • Нет, просто оставил соединение со всем блоком, т.е. заменило подзапрос. 08.11.2018
  • У меня выдает такую ​​ошибку: [42000][1055] Expression #4 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'ps.criteria' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by 08.11.2018
  • Кроме того, смогу ли я суммировать эти 3 строки для каждого пользователя? 08.11.2018
  • Конечно, просто замените ps.points в списке выбора на sum(ps.points) и удалите ps.id из предложения GROUP BY. 08.11.2018
  • Это дает мне результат 4439.000046, а также неправильное количество текущих пользовательских баллов... как это произошло? 08.11.2018
  • Трудно сказать, не глядя на ваши данные. Сначала запустите запрос без агрегирования ps.points, это должно дать вам лучшее представление о том, что происходит. 08.11.2018
  • Давайте продолжим это обсуждение в чате. 08.11.2018
  • Новые материалы

    Прогресс в технологии Трансформеров часть 3
    Многомасштабный управляющий сигнальный преобразователь для бесфазного синтеза движения (arXiv) Автор: Линтао Ван , Кун Ху , Лей Бай , Юй Дин , Ваньли Оуян , Чжиюн Ван . Аннотация:..

    Представляем поддержку компонентов Vue.js. Мгновенный HMR и многое другое.
    Хотя у FuseBox уже был плагин Vue, он был базовым и не имел многих функций, которые делали работу с Vue.js такой приятной. Однако с этим выпуском мы рады сообщить, что в FuseBox..

    Приключения в Javascript, часть 1
    Я продолжаю думать о том, чтобы писать больше, но чем больше я думаю об этом, тем меньше я это делаю. Итак, сегодня я перестал думать и начал писать. Отсюда можно только спускаться… В..

    Понимание дженериков в TypeScript: подробное руководство
    Введение TypeScript, строго типизированный надмножество JavaScript, хорошо известен своей способностью улучшать масштабируемость, удобочитаемость и ремонтопригодность приложений. Одной из..

    Учебные заметки JavaScript Object Oriented Labs
    Вот моя седьмая неделя обучения программированию. После ruby ​​и его фреймворка rails я начал изучать самый популярный язык интерфейса — javascript. В отличие от ruby, javascript — это более..

    Разбор строк запроса в vue.js
    Иногда вам нужно получить данные из строк запроса, в этой статье показано, как это сделать. В жизни каждого дизайнера/разработчика наступает момент, когда им необходимо беспрепятственно..

    Предсказание моей следующей любимой книги 📚 Благодаря данным Goodreads и машинному обучению 👨‍💻
    «Если вы не любите читать, значит, вы не нашли нужную книгу». - J.K. Роулинг Эта статья сильно отличается от тех, к которым вы, возможно, привыкли . Мне очень понравилось поработать над..