1

预先警告:我是 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|
---------------------

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

4

5 回答 5

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
于 2013-07-04T13:17:07.217 回答
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
于 2013-07-04T13:16:36.840 回答
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

摆弄这个

于 2013-07-04T13:23:39.163 回答
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没有按东西分区的花哨。编辑了我的查询,所以不使用它。

于 2013-07-04T13:35:32.560 回答
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

于 2013-07-04T14:25:34.467 回答