8

IDのすべての最小レコードを取得する必要があるSQLの選択に取り組んでいます。私の問題は、コードが機能していると思っていても、他の列に対して誤った値を返すことがよくあることです。これは、集計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

これが私のコードに実行させたいことです。

例の表から、学生がid#94を持っている個別のテストと科目の組み合わせごとの最小スコアを選択します

例の2つの(大幅に変更された)テーブルを次に示します(こことコードでもすべての列名を変更しました。

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

問題は、学期の列(およびライブ作業で使用している他のすべての列)の値が間違ってしまうことです。

これでどこにも行けないのに長い時間がかかったことを考えると、2つのサンプルデータベースを作成するための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');

アドバイスやヒントをいただければ幸いです。公開してから1週間後に、あなたの作業が間違っていることに気付くのは非常に恥ずかしいことです。

4

7 に答える 7

4

MySQLでは、groupではなくselectにフィールドを含めると、任意の値が得られます。この場合、希望する結果が得られないため、単に学期とテスト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フィドルデモ

もう1つのあまり一般的ではない方法は、不等式に自己反結合することです。

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フィドルデモ

タイブレーカーの作成に興味がある場合は、または条件を追加するだけです

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デモ注:同点の状況を含めるようにデータを変更しました

于 2012-10-24T19:52:21.043 に答える
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 FiddlewithDemoを参照してください

于 2012-10-24T19:53:14.367 に答える
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
            )

SQLフィドルを使用したデモ

于 2012-10-24T20:34:18.333 に答える
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フィドルデモ

于 2012-10-24T19:54:27.890 に答える
1

2つのexample_student_scoresのスコアが同じである場合は、出力の重複を避ける必要があります。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)
                )
        )
        ;
于 2012-10-24T20:03:56.970 に答える
0

次のクエリはあなたが望むことをしますか?

  SELECT  test, subject, MIN(score) as minscore
  FROM example_student_scores
  WHERE studentid=94
  GROUP BY test, subject
于 2012-10-24T19:54:33.943 に答える
0

必要な列をSELECTしてGROUPBYするだけです。

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句の他のすべての属性はGROUPBY句に含まれている必要があります。

クエリの残りの部分は私には良いと思います。

于 2012-10-24T19:57:59.097 に答える