简体   繁体   English

选择最大(计数)MySQL

[英]SELECT MAX(COUNT) MySQL

I am new to MySQL, and I have a task to do right now where I have three tables:我是 MySQL 新手,我现在有一个任务要做,我有三个表:

  1. students(id,name)学生(身份证,姓名)
  2. courses(id,name)课程(ID,名称)
  3. grades(id, student_id (FK), course_id(FK), grade)成绩(id,student_id(FK),course_id(FK),成绩)

I am supposed to我应该

fetch the name of the course that is the most registered by students and if there is any conflict or ties with other course, retrieve the course after sorting ascendingly.获取学生注册最多的课程名称,如果与其他课程有冲突或联系,则按升序检索该课程。

I tried several queries, but they are not 'efficient enough'我尝试了几个查询,但它们“不够高效”

SELECT course.name FROM (
SELECT CI ,MAX(Total) FROM 
(
    SELECT course_id as CI,COUNT(*) AS Total 
    FROM grades
    GROUP BY course_id ASC
) AS Results

) AS x

INNER JOIN courses ON x.CI = courses.id

And

SELECT courses.name FROM (
SELECT course_id, COUNT(*) AS how_many
    FROM grades
    GROUP BY course_id ASC
    HAVING how_many = (
        SELECT COUNT(*) AS how_many
            FROM grades
            GROUP BY course_id
            ORDER BY how_many DESC
            LIMIT 1
    )
    LIMIT 1
) AS X
JOIN courses ON X.course_id=courses.id

Is there any more efficient query?有没有更高效的查询?

Both your query attempts look logically incorrect to me.在我看来,您的两次查询尝试在逻辑上都不正确。 You should be joining courses to grades to obtain the number of students enrolled in each course.您应该将courses加入到grades中,以获取每门课程注册的学生人数。 Regarding efficiency, the RANK analytic function is one of the most performant options, assuming you are running MySQL 8+:关于效率,假设您运行 MySQL 8+, RANK分析函数是性能最高的选项之一:

WITH cte AS (
    SELECT c.id, c.name, RANK() OVER (ORDER BY COUNT(*) DESC, c.name) rnk
    FROM courses c
    INNER JOIN grades g ON g.course_id = c.id
    GROUP BY c.id, c.name
)

SELECT id, name
FROM cte
WHERE rnk = 1;

On earlier versions of MySQL, we can use a LIMIT query:在早期版本的 MySQL 中,我们可以使用LIMIT查询:

SELECT c.id, c.name
FROM courses c
INNER JOIN grades g ON g.course_id = c.id
GROUP BY c.id, c.name
ORDER BY COUNT(*) DESC, c.name
LIMIT 1;

You can use the ORDER BY clause with the LIMIT clause to get what you need, without aggregating twice:您可以使用带有LIMIT子句的ORDER BY子句来获得所需的内容,而无需聚合两次:

WITH enrollments AS (
    SELECT course_id, COUNT(DISTINCT student_id) AS num_enrollments
    FROM grades
    GROUP BY course_id
)
SELECT * 
FROM       enrollments e
INNER JOIN courses c
        ON e.course_id = c.id
ORDER BY e.num_enrollments DESC, c.name ASC
LIMIT 1

The subquery will get you the enrollments by aggregating on the students, then it is joined with the courses to use the course name.子查询将通过聚合学生来获取注册信息,然后将其与课程连接以使用课程名称。

Data is then ordered by:然后数据按以下顺序排序:

  • number of enrollments descendent入学人数
  • course name ascendent课程名称升序

and only the first row is considered.并且只考虑第一行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM