选择两个不同值的最小值

时间:2012-10-24 19:41:55

标签: mysql sql aggregate-functions

我正在进行sql选择,我需要获取ID的所有最小记录。我的问题是,虽然我认为我的代码正在运行,但它通常会返回其他列的错误值,显然是因为我没有使用必须支持我的聚合min函数。这是我的代码。

SELECT *
FROM example_students
INNER JOIN
(SELECT  id, student, test, subject, MIN(score), semester
FROM example_student_scores
WHERE studentid=94
GROUP BY studentid, test, subject) as scores
ON example_students.id=scores.studentid

这就是我希望我的代码要做的事情。

  

从exampletable中选择每个不同的测试和主题组合的最低分数,其中学生具有id#94

以下是该示例的两个(经过大量修改的)表格(我在此处和我的代码中更改了所有列名称。

example_students
id    name
----+-----------+
94    Bob
1023  Thomas

example_students_scores
id    studentId     test       subject     score       semester
----+-----------+-----------+-----------+-----------+-----------

0    94          quiz        math        46          fall
1    94          quiz        math        71          fall
2    94          quiz        math        63          winter
3    94          midterm     math        94          winter
4    94          midterm     science     72          fall
5    94          quiz        math        50          spring
6    94          final       math        76          spring
7    1023        quiz        math        6           spring
8    1023        quiz        math        52          winter
9    1023        quiz        science     68          fall
..*

,结果应为

results
id    studentId     test       subject     score       semester
----+-----------+-----------+-----------+-----------+-----------
0    94          quiz        math        46          fall
3    94          midterm     math        94          winter
4    94          midterm     science     72          fall
6    94          final       math        76          spring

问题是,我会为学期专栏(以及我在实际工作中的所有其他专栏)得到错误的值。

鉴于这需要很长时间才能得到无处,这里是sql来创建两个示例数据库:

drop table if exists example_students;
drop table if exists example_students_scores;
create table example_students(
    id int(10) primary key,
    name char(25)
);
create table example_students_scores(
    id int(10) not null,
    studentId int(10) not null,
    test char(20),
    subject char(20),
    score int(10) not null default '0',
    semester char(20),
    primary key (id),
    index studentid (studentid)
);
insert into example_students values ('94','Bob');
insert into example_students values ('1023','Thomas');
insert into example_students_scores values ('0'    ,'94'          ,'quiz'        ,'math'        ,'46'          ,'fall');
insert into example_students_scores values ('1'    ,'94'          ,'quiz'        ,'math'        ,'71'          ,'fall');
insert into example_students_scores values ('2'    ,'94'          ,'quiz'        ,'math'        ,'63'          ,'winter');
insert into example_students_scores values ('3'    ,'94'          ,'midterm'     ,'math'        ,'94'          ,'winter');
insert into example_students_scores values ('4'    ,'94'          ,'midterm'     ,'science'     ,'72'          ,'fall');
insert into example_students_scores values ('5'    ,'94'          ,'quiz'        ,'math'        ,'50'          ,'spring');
insert into example_students_scores values ('6'    ,'94'          ,'final'       ,'math'        ,'76'          ,'spring');
insert into example_students_scores values ('7'    ,'1023'        ,'quiz'        ,'math'        ,'6'           ,'spring');

我会感激任何指示或提示,只是在上线一周后才弄清楚你的工作是错误的,这是非常尴尬的!

7 个答案:

答案 0 :(得分:4)

在MySQL中,当您在选择中包含字段而不在组中时,您将获得任意值。在这种情况下,您不能简单地在组中包含学期和测试ID,因为您将无法获得所需的结果。

为了实现这一目标,你必须找到每个学生,考试,科目的最低分数,然后将其重新加入原始表格

SELECT * 
FROM   example_students_scores ess 
       INNER JOIN (SELECT studentid, 
                          test, 
                          subject, 
                          Min(score) score 
                   FROM   example_students_scores 
                   WHERE  studentid = 94 
                   GROUP  BY studentid, 
                             test, 
                             subject) scores 
               ON ess.studentid = scores.studentid 
                  AND ess.test = scores.test 
                  AND ess.subject = scores.subject 
                  AND ess.score = scores.score 

SQL Fiddle Demo

另一种不太常规的方法是对不等式进行自反连接。

SELECT 
    s.*
FROM
    example_students_scores s
    LEFT JOIN example_students_scores s2
    ON s.studentID = s2.studentID
      AND s.test = s2.test
      AND s.subject = s2.subject
      AND s.score > s2.score
WHERE 
     s.studentid = 94 
     AND 
     s2.score is null

SQL Fiddle Demo

如果您对创建平局破坏者感兴趣,只需添加一个或条件

SELECT 
    s.*
FROM
    example_students_scores s
    LEFT JOIN example_students_scores s2
    ON s.studentID = s2.studentID
      AND s.test = s2.test
      AND s.subject = s2.subject
      AND (s.score > s2.score
           or s.id > s2.id ) -- Added for tie breaker

WHERE 
     s.studentid = 94 
     AND 
     s2.score is null

SQL Fiddle Demo注意:我修改了数据以包含平局情况

答案 1 :(得分:2)

这应该适合你:

select ss2.id score_id,
  ss2.studentid,
  ss1.test,
  ss2.subject,
  ss1.score,
  ss2.semester
from example_students st
left join
(
  select min(score) score, test, subject, studentid
  from example_students_scores
  group by test, studentid, subject
) ss1
  on st.id = ss1.studentid
left join example_students_scores ss2
  on st.id = ss2.studentid
  and ss1.score = ss2.score
  and ss1.test = ss2.test
where st.id = 94
order by ss2.id

请参阅SQL Fiddle with Demo

答案 2 :(得分:1)

试试这个解决方案:

select es.name, e.studentid, e.test, e.subject, e.score as MinScore, e.semester 
from  example_students_scores e
join (
       select studentid, test, subject, min(score) as score
       from example_students_scores
        group by studentid, test, subject) e2 on  e.studentid=e2.studentid
                                              and e.test=e2.test 
                                              and e.subject=e2.subject
                                              and e.score=e2.score
join example_students es on e.studentid = es.id

SQL Fiddle演示

答案 3 :(得分:1)

如果两个example_student_score碰巧具有相同的分数,则需要避免输出中的重复。 Min()会导致重复。

执行任务的一种很好的方法是使用窗口函数和row_number()。

如果窗口功能不可用,则以下方式模拟“第一组”功能可能是:

SELECT * 
FROM example_students es
JOIN example_student_scores ss ON ss.studentid= es.id
WHERE es.id = 94
AND NOT EXISTS (
        SELECT *
        FROM example_student_scores nx
        WHERE nx.studentid = ss.studentid
        AND nx.test = ss.test
        AND nx.subject = ss.subject
        AND ( nx.score < ss.score
                -- tie breaker
                OR ( nx.score == ss.score AND nx.id < ss.id)
                )
        )
        ;

答案 4 :(得分:1)

带相关子查询的

select 
   * 
from 
   example_students_scores s1 
where 
   studentId = 94 and 
   score  = (select 
                 min(score)
             from 
                 example_students_scores s2 
             where
                 s2.studentId = s1.studentId and 
                 s2.subject = s1.subject and 
                 s2.test = s1.test 
             group by 
                 studentId, test, subject
            )

Demo with SQL Fiddle

答案 5 :(得分:0)

以下查询是否符合您的要求?

  SELECT  test, subject, MIN(score) as minscore
  FROM example_student_scores
  WHERE studentid=94
  GROUP BY test, subject

答案 6 :(得分:0)

只需选择和分组所需的列:

SELECT *
FROM example_students
INNER JOIN
(SELECT studentid, test, subject, MIN(score), semester
FROM example_student_scores
GROUP BY studentid, test, subject,semester) scores
ON example_students.id=scores.studentid
WHERE studentid=94

在列上使用聚合函数时,SELECT子句中的所有其他属性必须出现在GROUP BY子句中。

查询的其余部分对我来说听起来不错。