在子查询中选择最大值

时间:2018-03-28 12:12:02

标签: mysql sql subquery max

我有这两个表:

学生:

| classId |                   email |  signUpDate |
|---------|-------------------------|-------------|
|       1 |        sebastian@usm.cl |  2018-01-01 |
|       1 |           javier@usm.cl |  2019-10-01 |
|       1 |          bastian@usm.cl |  2018-07-01 |
|       2 |        sebastian@usm.cl |  2018-05-04 |
|       2 |          bastian@usm.cl |  2018-01-01 |
|       3 |          bastian@usm.cl |  2018-12-05 |
|       3 |        sebastian@usm.cl |  2018-02-01 |
|       4 |     arturo.vidal@usm.cl |  2018-03-01 |
|       5 | sebastian@presidente.cl |  2018-03-01 |

类别:

select classId, email, max(signUpDate)
from Class
group by classId

我想显示注册每个classId的最后一个学生的名字。这意味着,我应该获得classId 1的名称,classId 2的名称等等。我首先获取邮件的解决方案(以后知道学生的名字)是这样的:

| ClassId |                   email | max(signUpDate) |
|---------|-------------------------|-----------------|
|       1 |        sebastian@usm.cl |      2019-10-01 |
|       2 |        sebastian@usm.cl |      2018-05-04 |
|       3 |          bastian@usm.cl |      2018-12-05 |
|       4 |     arturo.vidal@usm.cl |      2018-03-01 |
|       5 | sebastian@presidente.cl |      2018-03-01 |

它打印最大日期,这是好的,但它也会为每个日期打印错误的邮件:

if(!IsPostBack)

这是完全错误的()。因此,当我尝试连接获取名称的值时,我得到的值不正确。

换句话说,我不明白为什么行会混淆。是否有任何解决方案可以为每个ClassId获取max(signUpDate)的正确电子邮件?

感谢您的时间

3 个答案:

答案 0 :(得分:2)

我创建了测试数据小提琴,并提出了一个简单易懂的查询来获取所需的数据,即:

SELECT DISTINCT classId,
                std.name,
                Class.email,
                signUpDate
FROM CLASS
INNER JOIN Student std ON std.email = Class.email
WHERE signUpDate IN
    (SELECT max(signUpDate)
     FROM CLASS
     GROUP BY classId)

Sql Fiddle here

答案 1 :(得分:1)

这是一个非常常见的问题的实例:找到最大化某个值(在组中)的字段FOR FOR EACH GROUP的整行。在您的情况下,您希望GROUP BY为ClassId,并且对于每个组中的每个组,您希望该字段的整行具有最大signupDate。

简短回答:您可以使用此查询:

SELECT 
    C.ClassId, 
    S.name
FROM
(
    SELECT A.* 
    FROM Class AS A 
    LEFT JOIN Class AS B 
    ON A.email = B.email AND A.signupDate < B.signupDate 
    WHERE B.email IS NULL
) AS C
LEFT JOIN Student AS S ON S.email=C.email

LONG ANSWER:

Here你可以找到我刚才所说的非常明确的解释。

假设我们可以使用您桌子上的电子邮件作为唯一标识符,您可以首先进行表格的加入(在电子邮件字段中)&#34; Class&#34;与自己一起,选择&#34;最大日期&#34;对于每个班级ID。之后,您加入(在电子邮件字段中)表格&#34;学生&#34;。之后,您将拥有一个包含&#34; Class&#34;的所有字段的表格。表和学生的所有领域&#34;表。您可以选择所需的字段。在下面的例子中,我将选择&#34; Class.classId&#34;和#34; Student.name&#34;

如果您运行此查询:

SELECT A.* 
FROM Class AS A 
LEFT JOIN Class AS B 
ON A.email = B.email AND A.signupDate < B.signupDate 
WHERE B.email IS NULL

您获得此表:

+---------+-------------------------+------------+
| ClassId | email                   | signupDate |
+---------+-------------------------+------------+
|       1 | javier@usm.cl           | 2019-10-01 |
|       2 | sebastian@usm.cl        | 2018-05-04 |
|       3 | bastian@usm.cl          | 2018-12-05 |
|       4 | arturo.vidal@usm.cl     | 2018-03-01 |
|       5 | sebastian@presidente.cl | 2018-03-01 |
+---------+-------------------------+------------+

现在您可以将其与表格#34;学生&#34;加入,然后选择您想要的字段。如果您运行&#34;简短回答中提供的查询&#34;这篇文章的一部分,你得到以下结果:

+---------+--------------------+
| ClassId | name               |
+---------+--------------------+
|       4 | Arturo Vidal       |
|       3 | Bastian Quezada    |
|       1 | Javier Jeria       |
|       5 | Sebastian Piñera   |
|       2 | Sebastian Gallardo |
+---------+--------------------+

答案 2 :(得分:0)

试试这个:

SELECT A.classId, C.name, C.email, B.signUpDate
FROM
(SELECT classId, max(signUpDate) maxSignUpDate
FROM Class
GROUP BY classId) A JOIN Class B
ON A.classId=B.classId AND A.maxSignUpDate=B.signUpDate
JOIN Student C ON C.email=B.email;

我假设该电子邮件是Student表的ID字段。有关见解,请参见MySQL Join Made EasyMySQL GROUP BY

SQL Fiddle.

上查看它