MySQL 根据最大值连接表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1863606/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 14:42:44  来源:igfitidea点击:

Joining tables based on the maximum value

sqlmysqlsql-serveroraclejoin

提问by nickf

Here's a simplified example of what I'm talking about:

这是我正在谈论的一个简化示例:

Table: students      exam_results
_____________       ____________________________________
| id | name |       | id | student_id | score |   date |
|----+------|       |----+------------+-------+--------|
|  1 | Jim  |       |  1 |          1 |    73 | 8/1/09 | 
|  2 | Joe  |       |  2 |          1 |    67 | 9/2/09 |
|  3 | Jay  |       |  3 |          1 |    93 | 1/3/09 |
|____|______|       |  4 |          2 |    27 | 4/9/09 |
                    |  5 |          2 |    17 | 8/9/09 |
                    |  6 |          3 |   100 | 1/6/09 |
                    |____|____________|_______|________|

Assume, for the sake of this question, that every student has at least one exam result recorded.

为了这个问题,假设每个学生至少记录了一个考试结果。

How would you select each student along with their highest score?Edit: ...AND the other fields in that record?

你会如何选择每个学生以及他们的最高分?编辑:...和该记录中的其他字段?

Expected output:

预期输出:

_________________________
| name | score |   date |
|------+-------|--------|
|  Jim |    93 | 1/3/09 |
|  Joe |    27 | 4/9/09 |
|  Jay |   100 | 1/6/09 |
|______|_______|________|

Answers using all types of DBMS are welcome.

欢迎使用所有类型的 DBMS 回答。

回答by boydc7

Answering the EDITED question (i.e. to get associated columns as well).

回答 EDITED 问题(即获取相关列)。

In Sql Server 2005+, the best approach would be to use a ranking/window functionin conjunction with a CTE, like this:

在 Sql Server 2005+ 中,最好的方法是将排名/窗口函数CTE结合使用,如下所示:

with exam_data as
(
    select  r.student_id, r.score, r.date,
            row_number() over(partition by r.student_id order by r.score desc) as rn
    from    exam_results r
)
select  s.name, d.score, d.date, d.student_id
from    students s
join    exam_data d
on      s.id = d.student_id
where   d.rn = 1;

For an ANSI-SQL compliant solution, a subquery and self-join will work, like this:

对于符合 ANSI-SQL 的解决方案,子查询和自联接将起作用,如下所示:

select  s.name, r.student_id, r.score, r.date
from    (
            select  r.student_id, max(r.score) as max_score
            from    exam_results r
            group by r.student_id
        ) d
join    exam_results r
on      r.student_id = d.student_id
and     r.score = d.max_score
join    students s
on      s.id = r.student_id;

This last one assumes there aren't duplicate student_id/max_score combinations, if there are and/or you want to plan to de-duplicate them, you'll need to use another subquery to join to with something deterministic to decide which record to pull. For example, assuming you can't have multiple records for a given student with the same date, if you wanted to break a tie based on the most recent max_score, you'd do something like the following:

最后一个假设没有重复的 student_id/max_score 组合,如果有和/或你想计划去重复它们,你需要使用另一个子查询来加入一些确定性的东西来决定要拉哪条记录. 例如,假设您不能拥有同一日期的给定学生的多个记录,如果您想根据最近的 max_score 打破平局,您可以执行以下操作:

select  s.name, r3.student_id, r3.score, r3.date, r3.other_column_a, ...
from    (
            select  r2.student_id, r2.score as max_score, max(r2.date) as max_score_max_date
            from    (
                        select  r1.student_id, max(r1.score) as max_score
                        from    exam_results r1
                        group by r1.student_id
                    ) d
            join    exam_results r2
            on      r2.student_id = d.student_id
            and     r2.score = d.max_score
            group by r2.student_id, r2.score
        ) r
join    exam_results r3
on      r3.student_id = r.student_id
and     r3.score = r.max_score
and     r3.date = r.max_score_max_date
join    students s
on      s.id = r3.student_id;

EDIT: Added proper de-duplicating query thanks to Mark's good catch in comments

编辑:由于 Mark 在评论中的出色表现,添加了适当的重复数据删除查询

回答by OMG Ponies

SELECT s.name,
    COALESCE(MAX(er.score), 0) AS high_score
FROM STUDENTS s
    LEFT JOIN EXAM_RESULTS er ON er.student_id = s.id
GROUP BY s.name

回答by Zinx

Try this,

尝试这个,

Select student.name, max(result.score) As Score from Student
        INNER JOIN
    result
        ON student.ID = result.student_id
GROUP BY
    student.name

回答by Jeffrey Kemp

With Oracle's analytic functions this is easy:

使用 Oracle 的分析功能,这很容易:

SELECT DISTINCT
       students.name
      ,FIRST_VALUE(exam_results.score)
       OVER (PARTITION BY students.id
             ORDER BY exam_results.score DESC) AS score
      ,FIRST_VALUE(exam_results.date)
       OVER (PARTITION BY students.id
             ORDER BY exam_results.score DESC) AS date
FROM   students, exam_results
WHERE  students.id = exam_results.student_id;

回答by MSH

Select Name, T.Score, er. date 
from Students S inner join
          (Select Student_ID,Max(Score) as Score from Exam_Results
           Group by Student_ID) T 
On S.id=T.Student_ID inner join Exam_Result er
On er.Student_ID = T.Student_ID And er.Score=T.Score

回答by Mark Byers

Using MS SQL Server:

使用 MS SQL 服务器:

SELECT name, score, date FROM exam_results
JOIN students ON student_id = students.id
JOIN (SELECT DISTINCT student_id FROM exam_results) T1
ON exam_results.student_id = T1.student_id
WHERE exam_results.id = (
    SELECT TOP(1) id FROM exam_results T2
    WHERE exam_results.student_id = T2.student_id
    ORDER BY score DESC, date ASC)

If there is a tied score, the oldest date is returned (change date ASCto date DESCto return the most recent instead).

如果有追平比分,最早的日期返回(其他城市date ASCdate DESC返回最近的代替)。

Output:

输出:

Jim 93  2009-01-03 00:00:00.000
Joe 27  2009-04-09 00:00:00.000
Jay 100 2009-01-06 00:00:00.000

Test bed:

试验台:

CREATE TABLE students(id int , name nvarchar(20) );

CREATE TABLE exam_results(id int , student_id int , score int, date datetime);

INSERT INTO students
VALUES
(1,'Jim'),(2,'Joe'),(3,'Jay')

INSERT INTO exam_results VALUES
(1, 1, 73, '8/1/09'), 
(2, 1, 93, '9/2/09'),
(3, 1, 93, '1/3/09'),
(4, 2, 27, '4/9/09'),
(5, 2, 17, '8/9/09'),
(6, 3, 100, '1/6/09')

SELECT name, score, date FROM exam_results
JOIN students ON student_id = students.id
JOIN (SELECT DISTINCT student_id FROM exam_results) T1
ON exam_results.student_id = T1.student_id
WHERE exam_results.id = (
    SELECT TOP(1) id FROM exam_results T2
    WHERE exam_results.student_id = T2.student_id
    ORDER BY score DESC, date ASC)

On MySQL, I think you can change the TOP(1) to a LIMIT 1 at the end of the statement. I have not tested this though.

在 MySQL 上,我认为您可以将语句末尾的 TOP(1) 更改为 LIMIT 1。不过我还没有测试过。