我有两个mysql最大n组,最新的问题:
考虑到一个学生表和一个成绩表,我想让所有学生都显示他们最近的成绩。
架构脚本:
CREATE TABLE student (
id int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO student VALUES(1, 'jim');
INSERT INTO student VALUES(2, 'mark ');
INSERT INTO student VALUES(3, 'john');
CREATE TABLE grades (
id int(11) NOT NULL AUTO_INCREMENT,
student_id int(11) NOT NULL,
grade int(11) NOT NULL,
`date` date DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO grades VALUES(1, 1, 6, NULL);
INSERT INTO grades VALUES(2, 1, 8, NULL);
INSERT INTO grades VALUES(3, 1, 10, NULL);
INSERT INTO grades VALUES(4, 2, 9, '2016-05-10');
INSERT INTO grades VALUES(5, 2, 8, NULL);
INSERT INTO grades VALUES(6, 3, 6, '2016-05-26');
INSERT INTO grades VALUES(7, 3, 7, '2016-05-27');
A)我想知道这是否是一个有效的解决方案,可以从一个日期字段(date
)中获取最新记录,该字段来自于为每行中的每一行分组的辅助表(grades
)主表(student
)。
我的查询是:
SELECT s.id, s.name, g.grade, g.date
FROM student AS s
LEFT JOIN (
SELECT student_id, grade, DATE
FROM grades AS gr
WHERE DATE = (
SELECT MAX(DATE)
FROM grades
WHERE student_id = gr.student_id
)
GROUP BY student_id
) AS g ON s.id = g.student_id
Sql Fiddle:http://sqlfiddle.com/#!9/a84171/2
此查询显示所需(几乎)结果。但我怀疑这是最好的方法,因为它看起来很难看,所以我对替代品非常好奇。
B)第二个问题是(almost)
以上的原因,
对于第一行name=Jim
,虽然我们有吉姆成绩,但它没有找到成绩。
因此,以防上述查询仅对NOT NULL日期字段有效。
问题是:
如何获得所有成绩的学生的最新成绩,包括Jim,即使他的成绩没有指定日期(NULL)。在这种情况下,最新的分组将由插入的最新行(MAX(id))或随机分配。
不能使用date = (SELECT...
替换date IN (SELECT ...
。
非常感谢任何帮助,
谢谢!
[更新#1]:
对于B)我发现将这个添加到子查询 OR date IS NULL
,产生了所需的结果:
SELECT s.id, s.name, g.grade, g.date
FROM student AS s
LEFT JOIN (
SELECT id, student_id, grade, DATE
FROM grades AS gr
WHERE DATE = (
SELECT MAX(DATE)
FROM grades
WHERE student_id = gr.student_id
) OR date IS NULL
GROUP BY student_id
) AS g ON s.id = g.student_id
[更新#2]
如果一年级有学生的日期,似乎上一次更新有效。如果第一年级为空,则不会。我会联系一个小提琴,但似乎sqlfiddle现在不起作用。
所以这就是我到现在为止解决B)问题的方法:
SELECT s.id, s.name, g.grade, g.date
FROM student AS s
LEFT JOIN (
SELECT id, student_id, grade, DATE
FROM grades AS gr
WHERE (
`date` = (
SELECT MAX(DATE)
FROM grades
WHERE student_id = gr.student_id
)
) OR (
(
SELECT MAX(DATE)
FROM grades
WHERE student_id = gr.student_id
) IS NULL AND
date IS NULL
)
) AS g ON s.id = g.student_id
GROUP BY student_id
我仍然想知道你们是否知道更好的替代方案。
谢谢!
[更新#3]
@Strawberry 期望的结果将是:
id name grade date
1 jim 10 NULL
2 mark 9 2016-05-10
3 john 7 2016-05-27
答案 0 :(得分:1)
这个问题的复杂性源于没有相关日期的成绩的逻辑上的不可能性,所以显然解决方案是解决这个问题。
但这是一个解决方法......
E.g:
SELECT a.*
FROM grades a
JOIN
( SELECT student_id
, MAX(COALESCE(UNIX_TIMESTAMP(date),id)) date
FROM grades
GROUP
BY student_id
) b
ON b.student_id = a.student_id
AND b.date = COALESCE(UNIX_TIMESTAMP(a.date),id);
答案 1 :(得分:0)
http://sqlfiddle.com/#!9/ecec43/4
SELECT s.id, s.name, g.grade, g.date
FROM student AS s
LEFT JOIN (
SELECT gr.student_id, gr.grade, gr.DATE
FROM grades AS gr
LEFT JOIN grades grm
ON grm.student_id = gr.student_id
AND grm.date>gr.date
WHERE grm.student_id IS NULL
AND gr.date IS NOT NULL
GROUP BY gr.student_id
) AS g
ON s.id = g.student_id;