MySQL - сложный COUNT-запрос - PullRequest
2 голосов
/ 28 марта 2012

У меня есть таблица с именем user_scores, как показано ниже:

id | af_id | uid | level | record_date
----------------------------------------
1  | 1.1   | 1   | 3     | 2012-01-01
2  | 1.1   | 1   | 4     | 2012-02-01
3  | 1.2   | 1   | 3     | 2012-01-01
4  | 1.2   | 1   | 5     | 2012-03-01
...

У меня есть еще одна таблица с именем user_info, как показано ниже:

uid | forename | surname | gender 
-----------------------------------
1   | Homer    | Simpson | M
2   | Marge    | Simpson | F
3   | Bart     | Simpson | M
4   | Lisa     | Simpson | F
...

В пользовательских счетах uid - это идентификатор пользователя зарегистрированногоПользователь в системе, af_id идентифицирует конкретный тест, который пользователь отправляет.Пользователь оценивает уровень от 1 до 5 для каждого теста, который можно отправлять каждый месяц.

Моя проблема в том, что мне нужно произвести анализ в конце года, чтобы СЧИТАТЬ количество достигнутых пользователей.каждый уровень для конкретного теста.Анализ должен показать гендерное разделение для мужчин и женщин.

Так, например, администратор выбрал бы тест 1.1, и система генерировала бы статистику на основе СЧЕТА общего уровня МАКС, достигнутого каждым пользователем в году, с разбивкой по полу.

Любойпомощь очень ценится.Заранее спасибо.

-

Думаю, мне нужно немного прояснить себя.Поскольку пользователь может пройти тест несколько раз в течение года, для одного и того же теста будет несколько баллов.Запрос должен принимать наивысший достигнутый уровень и включать его в счетчик.Пример результата будет:

Male Results: 
level1 | level2 | level3 | level4 | level5 
------------------------------------------
2      | 5      | 10     | 8      | 1

Ответы [ 5 ]

2 голосов
/ 28 марта 2012

Предполагается, что record_date содержит только даты (без частей времени):

SELECT
  s.maxlevel,
  COUNT(NULLIF(gender, 'F')) AS M,
  COUNT(NULLIF(gender, 'M')) AS F
FROM user_info u
  INNER JOIN (
    SELECT
      uid,
      MAX(level) AS maxlevel
    FROM user_scores
    WHERE record_date > DATE_SUB(CURDATE(), INTERVAL DAYOFYEAR(CURDATE()) DAY)
      AND af_id = '1.1'
    GROUP BY
      uid
  ) s ON s.uid = u.uid
GROUP BY
  s.maxlevel

Это покажет вам только максимальные уровни, найденные в таблице user_scores. Если у вас есть таблица Levels, в которой перечислены все возможные уровни (от 1 до 5), вы можете использовать эту таблицу, чтобы получить полный список уровней. Если некоторые уровни отсутствуют в запрошенном подмножестве данных, соответствующие строки будут отображать 0 s в обоих столбцах.

Вот приведенный выше скрипт с небольшими изменениями, чтобы показать полный график уровней:

SELECT
  <b>l.level AS maxlevel</b>,
  COUNT(NULLIF(gender, 'F')) AS M,
  COUNT(NULLIF(gender, 'M')) AS F
FROM user_info u
  INNER JOIN (
    SELECT
      uid, MAX(level) AS maxlevel
    FROM user_scores
    WHERE record_date > DATE_SUB(CURDATE(), INTERVAL DAYOFYEAR(CURDATE()) DAY)
      AND af_id = '1.1'
    GROUP BY
      uid
  ) s ON s.uid = u.uid
  <b>RIGHT JOIN Levels l ON s.maxlevel = l.level</b>
GROUP BY
  <b>l.level</b>
2 голосов
/ 28 марта 2012

Я не уверен, что понял, что вы имеете в виду, но, как всегда, я пойду. Насколько я понимаю, вы хотите знать, сколько людей от каждого пола достигли каждого уровня в определенный год.

SELECT  MaxLevel, 
        COUNT(CASE WHEN ui.Gender = 'M' THEN 1 END) AS Males,
        COUNT(CASE WHEN ui.Gender = 'F' THEN 1 END) AS Females
FROM    User_Info ui
        INNER JOIN
        (   SELECT  MAX(Level) AS MaxLevel, 
                    UID
            FROM    User_Scores us
            WHERE   af_ID = '1.1'
            AND     YEAR(Record_Date) = 2012
            GROUP BY UID
        ) AS MaxUs
            ON MaxUs.uid = ui.UID
GROUP BY MaxLevel

Я поместил несколько примеров данных на SQL Fiddle , чтобы вы увидели, что это то, что вам нужно.

EDIT Чтобы транспонировать данные таким образом, чтобы уровни находились вдоль верхней части, а пол в строках работал следующим образом:

SELECT  Gender, 
        COUNT(CASE WHEN MaxLevel = 1 THEN 1 END) AS Level1,
        COUNT(CASE WHEN MaxLevel = 2 THEN 1 END) AS Level2,
        COUNT(CASE WHEN MaxLevel = 3 THEN 1 END) AS Level3,
        COUNT(CASE WHEN MaxLevel = 4 THEN 1 END) AS Level4,
        COUNT(CASE WHEN MaxLevel = 5 THEN 1 END) AS Level5
FROM    User_Info ui
        INNER JOIN
        (   SELECT  MAX(Level) AS MaxLevel, 
                    UID
            FROM    User_Scores us
            WHERE   af_ID = '1.1'
            AND     YEAR(Record_Date) = 2012
            GROUP BY UID
        ) AS MaxUs
            ON MaxUs.uid = ui.UID
GROUP BY Gender

Обратите внимание, что если существует более 5 уровней, вам нужно добавить больше в оператор select или начать создавать динамический SQL.

0 голосов
/ 28 марта 2012

Надеюсь, это то, что вы ищете!

Показать количество записей группы по идентификатору пользователя и полу максимального балла для af_id '1.1'.

select count(*), info.uid, info.gender, max(score.level)
from user_info as info 
join user_scores as score
  on info.uid = score.uid
where score.af_id = '1.1'
group by info.uid, info.gender;
0 голосов
/ 28 марта 2012

Вам нужно что-то вроде

SELECT
  uid,
  MAX(level)
WHERE
  record_date BETWEEN '2012-01-01' AND '2012-12-31'
  AND af_id='1.1'
GROUP BY uid

Если вам нужно разделение по полу, то в зависимости от того, какая вам нужна статистика по полу, вы можете добавить в этот запрос JOIN на таблицу user_info (чтобы получить MAX для пола), чтобы обернуть это как подзапрос и JOIN на все дело.

0 голосов
/ 28 марта 2012

ИЗМЕНЕНО на основании ваших правок.

 select sum(if(a.gender="M",1,0)) Male_users, sum(if(a.gender="F",1,0)) Female_users
 from myTable a where 
    a.level = (select max(b.level) from myTable b where a.uid=b.uid) 
 group by af_id.

Я набрал это в спешке. Но это должно сработать или, по крайней мере, доставить вас туда, куда вам нужно. НАПРИМЕР. если вам нужно указать временные рамки, добавьте это.

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