这是亚马逊的一个面试问题,用来测试基本的SQL技能,我有点失败了。请考虑以下表格:
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
我以为你可以有一张表B,你可以在其中单独获得最高分,并将其与学生表A中的名字相匹配。但结果证明我的“groupby”是错误的。
我觉得问题的另一个变体是,如果有一个以上的学生在一个科目中具有最高分,那么即使他们的名字也应该被包括在内。
请帮助解决这些问题。它们似乎很简单,但我无法掌握它。
谢谢!
答案 0 :(得分:4)
您只需将问题划分为一些大小的步骤并逐个解决
首先,获得每个科目的最高分:
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;
然后获取学生的姓名,而不是仅显示学生ID:
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元组测试仍然是任何其他名称的连接:
转换此..
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
):
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
答案 1 :(得分: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
Marks
,Student
和Subject
以查找该最高分的相关详细信息这也照顾了最高分的重复学生
结果:
STUDENTNAME SUBJECTNAME MARK
Alfred English 87
Betty Maths 82
Chris Maths 82
Chris Science 83
答案 2 :(得分: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
这是:
只有获得最高分的学生才能满足所有三种参赛条件。这列出了所有获得该最高分的学生,因此如果有关系,则两者都列出。
答案 3 :(得分:0)
我喜欢使用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
答案 4 :(得分:0)
只是为了好玩,考虑一下对OP描述的非常直译的不同问题:“编写一个查询来打印在 中获得最大分数的学生的名单列表 主题。“
如果学生在任何 一个 科目中获得最高分,但是不一定在 所有 科目。由于OP提出的问题并未要求输出中的主题名称,这是一种似是而非的解释。
列出在所有科目中获得最高分的学生(如果有)的名字(不包括没有分数的科目,因为当时没有最大分数),我认为这是有效的,使用迈克尔的专栏名称SQL Fiddle,我改编了here。
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的名称。 (如果学生在某个科目中收到多个分数,则此查询会返回学生的姓名,只要其中一个分数是该科目的最高分。)
答案 5 :(得分:0)
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>
答案 6 :(得分:0)
使用子查询:
select m.subid, m.stid, m.mark
from marks m,
(select m2.subid, max(m2.mark) max_mark
from marks m2
group by subid) subq
where subq.subid = m.subid
and subq.max_mark = m.mark
order by 1,2;
将Rank与分区结合使用:
select subid, stid, mark
from (select m.subid, m.stid, m.mark,
rank() over (partition by m.subid order by m.mark desc) Mark_Rank
from marks m)
where Mark_Rank = 1
order by 1,2;
答案 7 :(得分:0)
select max(m.mark) as maxMarkObtained,su.Subname from Student s
inner join Marks m on s.Stid=m.Stid inner join [Subject] su on
su.Subid=m.Subid group by su.Subname
我已经执行了,这应该可行。
答案 8 :(得分:0)
Select S.StudentName
From Student S
where S.StudentID IN
(Select StudentID from (
( Select Max(MarkRate)as MarkRate,SubjectID From Mark Group by SubjectID)) MaxMarks, Mark
where MaxMarks.SubjectID= Mark.SubjectID AND MaxMarks.MarkRate=Mark.MarkRate)
答案 9 :(得分:0)
我将尝试使用CTE和窗口函数rank()进行一次查询来获得答案
创建表格
create table Students
(student_id int,
Name varchar(255),
details varchar(255));
create table Subject(
Sub_id int,
name varchar(255));
create table marks
(student_id int,
subject_id int,
mark int);
答案应该是包含以下字段的表格
学生姓名| subject_name |标记
计划执行步骤
with CTE as (select s.name, sb.name as subject_name, m.mark, rank() over(partition by sb.name order by m.mark desc) as rn
from Students s
join marks m on s.student_id = m.student_id
join subject sb
on sb.Sub_id = m.subject_id)
select name , subject_name, mark
from CTE
where rn = 1
答案 10 :(得分:-1)
SELECT subjectname,
studentname
FROM student s
INNER JOIN mark m
ON s.studid = m.studid
INNER JOIN subject su
ON su.subjectid = m.subjectid
INNER JOIN (
SELECT subjectid,
max(value) AS maximum
FROM mark
GROUP BY subjectid
) highmark h
ON h.subjectid = m.subjectid
AND h.maximum = m.value;