找到以前的增长

时间:2013-07-04 13:04:22

标签: mysql sql

预先警告:我是MySQL的新手,所以期待愚蠢的后续问题。

我正在编写一个跟踪学生考试成绩的应用程序。每个学生将在不同时间进行多项考试。我希望能够计算同一学生两次连续考试之间考试成绩的变化。这是我桌子的基本结构......

--------------------------------------------
| score_id | student_id |   date   | score |
--------------------------------------------
|         1|           1| 2011-6-1 |    15 |
|        21|           1| 2011-8-1 |    16 |
|       342|           1| 2012-3-1 |    18 |
|         4|           2| 2011-6-1 |    21 |
|        16|           2| 2011-8-1 |    20 |
|       244|           2| 2012-3-1 |    20 |
--------------------------------------------

我想从查询中返回的内容是......

---------------------
| score_id | growth |
---------------------
|         1|    NULL|
|        21|       1|
|       342|       2|
|         4|    NULL|
|        16|      -1|
|       244|       0|
---------------------

这与被问及 here 的问题类似,但日期并不总是彼此分开的特定时间。

5 个答案:

答案 0 :(得分:1)

如果每个学生的分数ID是连续的,那么简单的联接将会:

select s.score_id, s.score - sprev.score
from scores s left outer join
     scores sprev
     on s.student_id = sprev.student_id and
        s.score_id = sprev.score_id + 1;
但是,如果输入数据实际上如此有序,我会感到惊讶。在这种情况下,您需要找到以前的学生分数。我认为相关子查询是最清楚的写法:

select score_id, score - prevscore
from (select s.*,
             (select score
              from scores s2
              where s.student_id = s2.student_id and
                    s.date > s2.date
              order by date desc
              limit 1
             ) as prevscore
      from scores s
     ) s

答案 1 :(得分:0)

这是非常低效的,不确定它是否可以优化,但我不知道你怎么能做你想要的,而不是每行发现额外的查询,但我没有花很多时间考虑优化路线,所以这只是一个解决方案,而不是最佳解决方案

SELECT score_id, (score-(SELECT score FROM table AS tbl2 WHERE tbl2.student_id=1 AND tbl2.score_id < tbl1.score_id ORDER BY tbl2.score_id DESC LIMIT 1)) AS growth FROM table as tbl1 WHERE tbl1.student_id=1

答案 2 :(得分:0)

试试这个

SELECT t1.score_id, t1.score - t2.score AS Growth
FROM Table1 t1
LEFT JOIN Table1 t2 on t1.score_id = t2.score_id + 1 and t1.student_id = t2.student_id

fiddle this

答案 3 :(得分:0)

这将是一个复杂的查询(虽然并非不可能 - 请参阅其他答案)。对于这些事情,我希望读取数据的发生更多,然后添加。因此,我会将最复杂的部分放在添加功能

如果您可以控制数据库的外观,我建议您在分数数据库中添加一个额外的列:

------------------------------------------------------------
| score_id | prev_score_id | student_id |   date   | score |
------------------------------------------------------------
|         1|          NULL |           1| 2011-6-1 |    15 |
|         2|             1 |           1| 2011-8-1 |    16 |
|         3|             2 |           1| 2012-3-1 |    18 |
|         4|          NULL |           2| 2011-6-1 |    21 |
|         5|             4 |           2| 2011-8-1 |    20 |
|         6|             5 |           2| 2012-3-1 |    20 |
------------------------------------------------------------

添加新得分记录时,您可以轻松找到prev_score_id:

select score_id
from score
where studentId = :studentId
and   date = ( select max(date)
               from score
               where studentId = :studentId
               and   date < :date )

现在,您的查询变得更加容易:

select current.score_id, current.score - previous.score as growth
from score current
left join score previous on current.prev_score_id = previous.score_id

编辑:刚才注意到mysql并不喜欢分区。编辑了我的查询,因此没有使用它。

答案 4 :(得分:0)

你走了,

SELECT STUDENT.SCORE_ID,TABLE1.CALSCORE FROM STUDENT LEFT OUTER JOIN
(SELECT S2.SCORE_ID,MIN(CASE WHEN S1.SCORE=S2.SCORE THEN NULL 
ELSE (S2.SCORE - S1.SCORE) END) CALSCORE
FROM STUDENT S1 INNER JOIN STUDENT S2
ON S1.student_id=S2.student_id
AND S1.DATE1 < S2.DATE1 AND S1.SCORE_ID < S2.SCORE_ID
GROUP BY S2.SCORE_ID) TABLE1 ON 
STUDENT.SCORE_ID=TABLE1.SCORE_ID

sqlfiddle