我有两个不同的表生和年级; 成绩表具有属性student_id,该属性引用来自学生表的student_id。 如何找到哪个学生的每个年级都存在?
如果不清楚,
Student ID Name
1 1 John
2 2 Paul
3 3 George
4 4 Mike
5 5 Lisa
Grade Student_Id Course Grade
1 1 Math A
2 1 English B
3 1 Physics C
4 2 Math A
5 2 English A
6 2 Physics B
7 3 Economics A
8 4 Art C
9 5 Biology A
Assume there is only grade a,b,c (no d, e or fail)
我只想找到John,因为他的A,B,C等级是 不应选择其他学生,例如Paul(2),因为他没有c年级。他选了哪门课程都没关系,我只需要确定他是否有所有可用的成绩即可。
感觉像我应该存在或sql中的所有函数一样,但不确定。 请帮忙。预先谢谢你。
答案 0 :(得分:6)
我会使用GROUP BY
和HAVING
,但是像这样:
SELECT s.Name
FROM Student s JOIN
Grade g
ON s.ID = g.Student_Id
GROUP BY s.id, s.Name
HAVING COUNT(DISTINCT g.Grade) = (SELECT COUNT(DISTINCT g2.grade) FROM grade g2);
您说“那里的所有成绩”,因此查询不应为此使用常量。
答案 1 :(得分:1)
您可以使用HAVING COUNT(DISTINCT Grade) = 3
来检查学生是否拥有所有3个年级:
SELECT Name
FROM Student S
JOIN Grade G ON S.ID = G.Student_Id
GROUP BY Name
HAVING COUNT(DISTINCT Grade) = 3
在联接上S.ID
对S.Student
进行猜测。不知道有什么区别。
答案 2 :(得分:1)
使用存在
select * from student s
where exists ( select 1
from grades g where g.Student_Id=s.ID
group by g.Student_Id
having count(distinct Grade)=3
)
示例
with Student as
(
select 1 as id,'John' as person
union all
select 2 as id,'Paul' as person
union all
select 3 as id,'jorge'
),
Grades as
(
select 1 as Graden, 1 as Student_Id, 'Math' as Course, 'A' as Grade
union all
select 2 as Graden, 1 as Student_Id, 'English' as Course, 'B' as Grade
union all
select 3 as Graden, 1 as Student_Id, 'Physics' as Course, 'C' as Grade
union all
select 4 as Graden, 2 as Student_Id, 'Math' as Course, 'A' as Grade
union all
select 5 as Graden, 2 as Student_Id, 'English' as Course, 'A' as Grade
union all
select 6 as Graden, 2 as Student_Id, 'Physics' as Course, 'B' as Grade
)
select * from Student s
where exists ( select 1
from Grades g where g.Student_Id=s.ID
group by g.Student_Id
having count(distinct Grade)=3
)
请注意having count(distinct Grade)=3
,因为您的示例数据等级类型为3
答案 3 :(得分:1)
在深入研究答案之前,这里有一个有效的SQL Fiddle Example,以便您可以实际操作。
正如戈登·利诺夫(Gordon Linoff)在他的excellent answer中指出的那样,您应该使用GroupBy
和Having Count(Distinct ... ) ...
作为检查的简便方法。
但是,我建议您更改设计,以确保您有针对每个问题的表格。
目前,您的Grade
表包含每个课程的每个学生的成绩。因此,它更像是StudentCourse
表(即,学生和课程的组合是唯一的/为您提供了该表的自然键)。您应该有一个实际的Grade
表,以提供可用成绩的列表;例如
create table Grade
(
Code char(1) not null constraint PK_Grade primary key clustered
)
insert Grade (Code) values ('A'),('B'),('C')
然后,如果您决定包括等级D和E,则可以确保您的查询仍然有效,而无需修改任何代码。它还确保您只需要查询一个小表即可获得完整的成绩列表,而不是一个潜在的大表。这样会带来更好的性能。最后,它还将帮助您维护良好的数据;也就是说,您不会因错别字而意外地被录取为X年级的学生;即由于验证/约束存在于数据库中。
select Name from Student s
where s.Id in
(
select sc.StudentId
from StudentCourse sc
group by sc.StudentId
having count(distinct sc.Grade) = (select count(Code) from Grade)
)
order by s.Name
同样,创建课程表是明智的。在这种情况下,为每个课程持有ID;因为将完整的课程名称保存在StudentCourse表中(如我们现在所说的那样)会占用更多空间,并且又缺乏验证/约束。因此,我建议修改您的数据库架构,使其看起来像这样:
create table Grade
(
Code char(1) not null constraint PK_Grade primary key clustered
)
insert Grade (Code) values ('A'),('B'),('C')
create table Course
(
Id bigint not null identity(1,1) constraint PK_Course primary key clustered
, Name nvarchar(128) not null constraint UK_Course_Name unique
)
insert Course (Name) values ('Math'),('English'),('Physics'),('Economics'),('Art'),('Biology')
create table Student
(
Id bigint not null identity(1,1) constraint PK_Student primary key clustered
,Name nvarchar(128) not null constraint UK_Student_Name unique
)
set identity_insert Student on --inserting with IDs to ensure the ids of these students match data from your question
insert Student (Id, Name)
values (1, 'John')
, (2, 'Paul')
, (3, 'George')
, (4, 'Mike')
, (5, 'Lisa')
set identity_insert Student off
create table StudentCourse
(
Id bigint not null identity(1,1) constraint PK_StudentCourse primary key
, StudentId bigint not null constraint FK_StudentCourse_StudentId foreign key references Student(Id)
, CourseId bigint not null constraint FK_StudentCourse_CourseId foreign key references Course(Id)
, Grade char /* allow null in case we use this table for pre-results; otherwise make non-null */ constraint FK_StudentCourse_Grade foreign key references Grade(Code)
, Constraint UK_StudentCourse_StudentAndCourse unique clustered (StudentId, CourseId)
)
insert StudentCourse (StudentId, CourseId, Grade)
select s.Id, c.Id, x.Grade
from (values
('John', 'Math', 'A')
,('John', 'English', 'B')
,('John', 'Physics', 'C')
,('Paul', 'Math', 'A')
,('Paul', 'English', 'A')
,('Paul', 'Physics', 'B')
,('George', 'Economics','A')
,('Mike', 'Art', 'C')
,('Lisa', 'Biology', 'A')
) x(Student, Course, Grade)
inner join Student s on s.Name = x.Student
inner join Course c on c.Name = x.Course