5

これは、基本的な SQL スキルをテストするために Amazon からのインタビューの質問として受けたもので、私は失敗しました。次の表を検討してください。

Student - Stid, Stname, Details
Subject - Subid, Subname
Marks - Stid, Subid, mark

各科目で最高点を獲得した学生の名前のリストを出力するクエリを作成します。

私が与えた間違った答えは次のとおりです。

select A.Stname from A as Student, B as 
(select Stid, Subid, max(mark) from Marks groupby Subid) where A.Stid = B.Stid

私はあなたがトップマークだけを取得し、それを学生テーブルAの名前と一致させることができるテーブルBを持つことができると思っていました.しかし、私の「グループバイ」が間違っていることがわかりました.

私が感じた質問のもう 1 つのバリエーションは、ある科目で最高点をとった学生が複数いる場合は、その名前も含めるべきだということです。

これらのクエリを解決するのを手伝ってくれませんか。シンプルに見えますが、私にはコツがつかめません。

ありがとう!

4

12 に答える 12

6

問題をいくつかの一口サイズのステップに分割し、それぞれを 1 つずつ解決する必要があります。

まず、各科目の最高得点を取得します。

select SubjectID, max(MarkRate)
from Mark
group by SubjectID;

次に、MarkRate が最大の SubjectID を持つユーザーをクエリします。

select SubjectID, MarkRate, StudentID
from Mark
where (SubjectID,MarkRate)
in
  (
  select SubjectID, max(MarkRate)
  from Mark
  group by SubjectID
  )
order by SubjectID, StudentID;

次に、StudentID だけを表示する代わりに、生徒の名前を取得します。

select SubjectName, MarkRate, StudentName
from Mark
join Student using(StudentID)
join Subject using(SubjectID)
where (SubjectID,MarkRate)
in
  (
  select SubjectID, max(MarkRate)
  from Mark
  group by SubjectID
  )
order by SubjectName, StudentName

結果の結合と関連付けに関するデータベース ベンダーの人為的な違いは別として、基本的な手順は同じです。まず、問題を一口サイズのパーツに分割し、それぞれを解いたときにそれらを統合して、それほど混乱しないようにします。


サンプルデータ:

CREATE TABLE Student
    (StudentID int, StudentName varchar(6), Details varchar(1));    
INSERT INTO Student
    (StudentID, StudentName, Details)
VALUES
    (1, 'John', 'X'),
    (2, 'Paul', 'X'),
    (3, 'George', 'X'),
    (4, 'Paul', 'X');

CREATE TABLE Subject
    (SubjectID varchar(1), SubjectName varchar(7));    
INSERT INTO Subject
    (SubjectID, SubjectName)
VALUES
    ('M', 'Math'),
    ('E', 'English'),
    ('H', 'History');

CREATE TABLE Mark
    (StudentID int, SubjectID varchar(1), MarkRate int);    
INSERT INTO Mark
    (StudentID, SubjectID, MarkRate)
VALUES
    (1, 'M', 90),
    (1, 'E', 100),
    (2, 'M', 95),
    (2, 'E', 70),
    (3, 'E', 95),
    (3, 'H', 98),
    (4, 'H', 90),
    (4, 'E', 100);

ここでのライブテスト: http://www.sqlfiddle.com/#!1/08728/3


IN tuple テストは、他の名前による結合です。

これを変換して..

select SubjectName, MarkRate, StudentName
from Mark
join Student using(StudentID)
join Subject using(SubjectID)

where (SubjectID,MarkRate)
in
  (
  select SubjectID, max(MarkRate)
  from Mark
  group by SubjectID
  )

order by SubjectName, StudentName

..参加する:

select SubjectName, MarkRate, StudentName
from Mark
join Student using(StudentID)
join Subject using(SubjectID)

join
  (
  select SubjectID, max(MarkRate) as MarkRate
  from Mark
  group by SubjectID
  ) as x using(SubjectID,MarkRate)

order by SubjectName, StudentName

このコードとその直後のコードを比較してください。独立したクエリでの JOIN が IN 構文のように見えることを確認してください。それらはほとんど同じように見え、IN が JOIN キーワードに置き換えられただけです。JOIN に置き換えられた IN キーワードは実際には長くなります。独立したクエリの列の結果 ( max(MarkRate) AS MarkRate) とサブクエリ自体 ( as x) にエイリアスを設定する必要があります。とにかく、これはスタイルの問題です。意図がより明確であるため、IN句を好みます。データ関係を反映するためだけに JOIN を使用する。

INとにかく、タプル test( )をサポートしていないすべてのデータベースで機能するクエリは次のとおりです。

select sb.SubjectName, m.MarkRate, st.StudentName
from Mark as m
join Student as st on st.StudentID = m.StudentID
join Subject as sb on sb.SubjectID = m.SubjectID

join
  (
  select SubjectID, max(MarkRate) as MaxMarkRate
  from Mark
  group by SubjectID
  ) as x on m.SubjectID = x.SubjectID AND m.MarkRate = x.MaxMarkRate

order by sb.SubjectName, st.StudentName

ライブ テスト: http://www.sqlfiddle.com/#!1/08728/4

于 2012-05-13T07:52:55.160 に答える
3
SQL> select * from stud;

 STUDENTID NAME                           DETAILS
---------- ------------------------------ ------------------------------
         1 Alfred                         AA
         2 Betty                          BB
         3 Chris                          CC

SQL> select * from subject;

 SUBJECTID NAME
---------- ------------------------------
         1 Maths
         2 Science
         3 English

SQL> select * from marks;

 STUDENTID  SUBJECTID       MARK
---------- ---------- ----------
         1          1         61
         1          2         75
         1          3         87
         2          1         82
         2          2         64
         2          3         77
         3          1         82
         3          2         83
         3          3         67

9 rows selected.

SQL> select name, subjectid, mark
  2  from (select name, subjectid, mark, dense_rank() over(partition by subjectid order by mark desc) rank
  3  from stud st, marks mk
  4  where st.studentid=mk.studentid)
  5  where rank=1;

NAME                            SUBJECTID       MARK
------------------------------ ---------- ----------
Betty                                   1         82
Chris                                   1         82
Chris                                   2         83
Alfred                                  3         87

SQL>
于 2015-09-23T18:15:45.030 に答える
2

私の試み-最大マークから始めて、そこから構築します

スキーマ:

CREATE TABLE Student (
  StudentId int,
  Name nvarchar(30),
  Details nvarchar(30)
)
CREATE TABLE Subject (
  SubjectId int,
  Name nvarchar(30)
)
CREATE TABLE Marks (
  StudentId int,
  SubjectId int,
  Mark int
)

データ:

INSERT INTO Student (StudentId, Name, Details) 
VALUES (1,'Alfred','AA'), (2,'Betty','BB'), (3,'Chris','CC')

INSERT INTO Subject (SubjectId, Name)
VALUES (1,'Maths'), (2, 'Science'), (3, 'English')

INSERT INTO Marks (StudentId, SubjectId, Mark)
VALUES 
(1,1,61),(1,2,75),(1,3,87),
(2,1,82),(2,2,64),(2,3,77),
(3,1,82),(3,2,83),(3,3,67)
GO

私のクエリは次のようになります。

;WITH MaxMarks AS (
  SELECT SubjectId, MAX(Mark) as MaxMark
    FROM Marks
    GROUP BY SubjectId
 )
SELECT s.Name as [StudentName], sub.Name AS [SubjectName],m.Mark
FROM MaxMarks mm
INNER JOIN Marks m 
ON m.SubjectId = mm.SubjectId 
AND m.Mark = mm.MaxMark
INNER JOIN Student s
ON s.StudentId = m.StudentId
INNER JOIN Subject sub
ON sub.SubjectId = mm.SubjectId

SQL フィドルの例

  1. 各科目の最高点を見つける
  2. に参加しMarks、その最高点の関連する詳細を見つけるStudentSubject

これにより、最高点の重複した学生も処理されます

結果:

STUDENTNAME SUBJECTNAME     MARK
Alfred  English     87
Betty   Maths           82
Chris   Maths           82
Chris   Science     83
于 2012-05-13T07:24:36.677 に答える
2

私は言ったでしょう:

select s.stname, s2.subname, highmarks.mark
from students s
join marks m on s.stid = m.stid
join Subject s2 on m.subid = s2.subid
join (select subid, max(mark) as mark
  from marks group by subid) as highmarks
    on highmarks.subid = m.subid and highmarks.mark = m.mark
order by subname, stname;

SQLFiddle はこちら: http://sqlfiddle.com/#!2/5ef84/3

これは:

  • 可能な学生を取得するために学生テーブルを選択します
  • 学生をマークに一致させるためのマーク テーブルへの結合、
  • サブジェクト ID を名前に解決するためのサブジェクト テーブルへの結合。
  • 各科目の最高点の派生テーブルへの結合。

最高点を獲得した学生のみが、3 つの参加条件をすべて満たします。これは、その最高点を取得したすべての学生をリストするため、同点の場合は両方がリストされます。

于 2012-05-13T07:43:45.147 に答える
1

Windows 関数を使用したシンプルなソリューションが気に入っています。

select t.*
from (select student.*, su.subname, max(mark) over (partition by subid) as maxmark
      from marks m join
           students st
           on m.stid = st.stid join
           subject su
           on m.subid = su.subid
     ) t
where t.mark = maxmark

または、代わりに:

select t.*
from (select student.*, su.subname, rank(mark) over (partition by subid order by mark desc) as markseqnum
      from marks m join
           students st
           on m.stid = st.stid join
           subject su
           on m.subid = su.subid
     ) t
where markseqnum = 1
于 2012-05-13T13:47:08.177 に答える
0

楽しみのために、OPの説明の非常に文字通りの解釈で得られる別の質問を考えてみてください。「科目で最高点を獲得した学生の名前のリストを印刷するクエリを作成してください。」

ここで回答した人は、学生が1つの科目で最高点を獲得したかどうかをリストするためのクエリを作成しました、必ずしもすべての科目で得点したわけではありません。OPによって提起された質問は、出力でサブジェクト名を要求しないため、これはもっともらしい解釈です。

すべての科目で最高点を獲得した学生の名前(ある場合)を一覧表示するには(おそらく、最高点がないため、点数のない科目を除く)、MichaelのSQLFiddleの列名を使用してこれが機能すると思います。私はここでそれを適応させました。

select StudentName
from Student 
where not exists (
  select * from Subject
  where exists (
    select * from Mark as M1
    where M1.SubjectID = Subject.SubjectID
    and M1.StudentID <> Student.StudentID
    and not exists (
      select * from Mark as M2
      where M2.StudentID = Student.StudentID
      and M2.SubjectID = M1.SubjectID
      and M2.MarkRate >= M1.MarkRate
    )
  )
)

つまり、その科目の誰かのマークが同じ科目のXに属するマークと一致しないか、それを超えていない科目がない場合は、学生のXの名前を選択します。(このクエリは、学生がサブジェクトで複数のマークを受け取った場合、それらのマークの1つがサブジェクトで最も高い場合に限り、学生の名前を返します。)

于 2012-05-14T00:18:17.750 に答える