2015-05-05 3 views
0

У меня есть одна таблица, в которой есть оценки людей.MYSQL присоединение проблемы подзапроса

+---------+--------+--------+--------+---------------------+ 
| name | grade1 | grade2 | grade3 |  datetime  | 
+---------+--------+--------+--------+---------------------+ 
| person1 |  50 |  80 | 100 | 2015-05-05 12:00:00 | 
| person1 |  60 |  43 |  88 | 2015-05-05 12:00:00 | 
| person1 |  11 |  80 |  44 | 2015-05-05 12:00:00 | 
| person1 |  64 |  75 |  37 | 2015-05-05 12:00:00 | 
| person1 |  83 |  34 |  99 | 2015-05-05 12:00:00 | 
| person2 |  45 | 100 |  95 | 2015-05-05 12:00:00 | 
| person2 |  76 |  75 |  54 | 2015-05-05 12:00:00 | 
| person2 |  68 |  53 |  66 | 2015-05-05 12:00:00 | 
| person2 |  45 |  12 |  85 | 2015-05-05 12:00:00 | 
| person2 |  75 |  78 |  55 | 2015-05-05 12:00:00 | 
+---------+--------+--------+--------+---------------------+ 

Что мне нужно сделать, это тянуть оценки человека в определенный день, а затем строка, представляющая их годен/негоден отчет от предыдущего (до 7) дней.

Конечный результат я бы искал на основе со стола будет что-то вроде этого:

+---------------+---------+--------+--------+--------+----------------+ 
| report  | name | grade1 | grade2 | grade3 | datetime | 
+---------------+---------+--------+--------+--------+----------------+ 
| pass:3 fail:2 | person1 |  50 |  80 | 100 | 5/5/2015 12:00 | 
| pass:2 fail:3 | person2 |  42 | 100 |  95 | 5/5/2015 12:00 | 
+---------------+---------+--------+--------+--------+----------------+ 

Так что мой SQL, чтобы получить первую часть довольно проста:

SELECT * 
FROM Grades.grade_table gt 
WHERE gt.datetime = '2015-05-05 12:00:00' 

Второй часть моего запроса выглядит следующим образом:

SELECT CONCAT('fail:',SUM(CASE WHEN pass_fail = 'fail' THEN 1 ELSE 0 END),' pass:',SUM(CASE WHEN pass_fail = 'pass' THEN 1 ELSE 0 END)) trend_data 
FROM (
    SELECT 
    CASE 
     WHEN ((grade1+grade2+grade3)/3) >= 65 THEN 'pass' 
     ELSE 'fail' 
    END AS pass_fail 
    FROM Grades.grade_table gt 
    WHERE gt.name = 'person1' 
    LIMIT 7 
) trend_data 

Что я пробовал:

SELECT 
(
    SELECT CONCAT('fail:',SUM(CASE WHEN pass_fail = 'fail' THEN 1 ELSE 0 END),' pass:',SUM(CASE WHEN pass_fail = 'pass' THEN 1 ELSE 0 END)) trend_data 
    FROM (
    SELECT 
    CASE 
     WHEN ((grade1+grade2+grade3)/3) >= 65 THEN 'pass' 
     ELSE 'fail' 
    END AS pass_fail 
    FROM Grades.grade_table gt 
    WHERE gt.name = original_data.name 
    LIMIT 7 
) trend_data 
) AS trending_data, original_data.* 
FROM 
(
    SELECT * 
    FROM Grades.grade_table gt 
    WHERE gt.datetime = '2015-05-05 12:00:00' 
) 

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

+0

Я создал здесь скрипт sql, если он вообще помогает: sqlfiddle.com/#!9/ac6d0/10/0 – CarlyL

+0

Я обновил свой ответ. Он должен соответствовать вашим требованиям сейчас. – mwilczynski

ответ

1

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

SQLfiddle:http://sqlfiddle.com/#!9/74eb5e/61

запрос для получения успеха и не:

SELECT name AS 'Name', 
    CONCAT(
     'Fail: ', 
     CAST(SUM(CASE WHEN (grade1+grade2+grade3)/3 <= 65 THEN 1 ELSE 0 END) AS CHAR(20)), 
     ' Success: ', 
     CAST(SUM(CASE WHEN (grade1+grade2+grade3)/3 > 65 THEN 1 ELSE 0 END) AS CHAR(20))) AS 'Report', 
     NOW() AS 'Report date' 
FROM grade_table gt1 
WHERE (SELECT COUNT(*) 
     FROM grade_table 
     WHERE name = gt1.name 
     AND gradedate > gt1.gradedate 
     ORDER BY gradedate ASC) < 7 
GROUP BY name; 

Edit 1:

Нового кода и обновленный SQLfiddle соответствует вашим требованиям (за последние семь дней каждого неудачи и успехи человека).

Edit 2:

В основном это более сложная проблема, которая хорошо описана здесь:

http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/

Как правило, вы не можете просто идти легко с LIMIT для такой оговорки, потому что вы хотите ограничить каждую группу (GROUP BY name). Однако вы можете использовать что-то вроде этого, чтобы получить Top N записей в группе:

SELECT name, gradedate 
FROM grade_table gt1 
WHERE (SELECT COUNT(*) 
     FROM grade_table 
     WHERE name = gt1.name 
     AND gradedate > gt1.gradedate 
     ORDER BY gradedate ASC) < 2 

Он будет проверять, если конкретная запись в группе имеет (COUNT(*)) меньше, чем две записи с большим (более поздней) даты. Это просто означает, что это может быть только эта запись и, возможно, одна из них.

Я обновил окончательное решение, чтобы оно соответствовало вашим потребностям. Обратите внимание, что решение не очень эффективно, хотя оно масштабируется с N возможностями имени. Я рекомендую вам ознакомиться с блоком, представленным в виде более подробных примеров и замечательных замечаний ниже статьи, которые трудно было бы обсудить здесь за короткое время.

+0

Это близко к тому, что я ищу. Причина, по которой я не могу найти только последние 7 дней, заключается в том, что некоторые результаты студентов больше 7 дней назад, а некоторые - нет. Мне нужно до 7 экземпляров данных студента, независимо от того, насколько далековато. – CarlyL

+0

Пожалуйста, проверьте решение, я думаю, что мы здесь. Вы можете попробовать протестировать его менее чем за 7 дней в разделе WHERE, чтобы вам не нужно было создавать больше данных образца. – mwilczynski

+0

Удивительно, я даже не был близок к моему подходу ... :( Спасибо за ваше решение и предоставленную ссылку в блоге! – CarlyL

Смежные вопросы