健康一贴灵,专注医药行业管理信息化

转:SQL Server 基础之《学生表-教师表-课程表-选课表》

SQL Server 基础之《学生表-教师表-课程表-选课表》

 

数据库表结构及数据

建表

 View Code

测试数据

 View Code

数据库多表查询之 where & INNER JOIN

在多表查询中,一些SQL开发人员更喜欢使用WHERE来做join,比如:

SELECT a.ID, b.Name, b.Date FROM Customers a, Sales b WHERE a.ID = b.ID;

  WHERE子句中使用的连接语句,在数据库语言中,被称为隐性连接。INNER JOIN……ON子句产生的连接称为显性连接。(其他JOIN参数也是显性连接)WHERE 和INNER JOIN产生的连接关系,没有本质区别,结果也一样。但是!隐性连接随着数据库语言的规范和发展,已经逐渐被淘汰,比较新的数据库语言基本上已经抛弃了隐性连接,全部采用显性连接了。

  缺点:在上面语句中,实际上是创建了两张表的笛卡尔积,所有可能的组合都会被创建出来。在笛卡尔连接中,在上面的例子中,如果有1000顾客和1000条销售记录,这个查询会先产生1000000个结果,然后通过正确的 ID过滤出1000条记录。 这是一种低效利用数据库资源,数据库多做100倍的工作。 在大型数据库中,笛卡尔连接是一个大问题,对两个大表的笛卡尔积会创建数10亿或万亿的记录。

为了避免创建笛卡尔积,应该使用INNER JOIN :

SELECT a.ID, b.Name, b.Date FROM Customers a INNER JOIN Sales b ON a.ID = b.ID;

  优点:如上面语句,使用inner join 这样数据库就只产生等于ID 的1000条目标结果。增加了查询效率。

练习题目

1.查询“001”课程比“002”课程成绩高的所有学生的学号;

1
2
3
4
select from
(select S#,Score from SC where C#='001') a,
(select S#,Score from SC where C#='002') b
where a.S#=b.S# and a.Score>b.Score

       

2.查询平均成绩大于60分的同学的学号和平均成绩;
方法一:

1
2
3
4
select from
(select S#,AVG(score) as av from sc
group by S# ) S
where S.av>60

方法二:

1
2
3
4
select S#,AVG(Score) as AvgScore
from SC
group by S#
having AVG(Score)>60

      

3.查询所有同学的学号、姓名、选课数、总成绩;

1
2
3
4
5
select S.S#,S.Sname,COUNT(C#) as CourseCount, SUM(score) as ScoreSum
from Student as left join Sc as C
on S.S#=C.S#
group by S.S#,S.Sname
order by S.S#

       

4.查询姓“李”的老师的个数;

1
select count(distinct Tname) as count from Teacher where Tname like '李%'

      

5.查询没学过“叶平”老师课的同学的学号、姓名;

1
2
3
4
select S.S#,S.Sname
from Student as S
where S.S# not in
(select distinct(sc.S#) from SC sc,Course c,Teacher t where sc.C#=c.C# and c.T#=t.T# and t.Tname='叶平')

      

 6.查询学过“001”并且也学过编号“002”课程的同学的学号、姓名;

复制代码
--解法一:求交集
select s.S#,s.Sname
from Student s,SC sc
where s.S#=sc.S# and sc.C#='001'
intersect
select s.S#,s.Sname
from Student s,SC sc
where s.S#=sc.S# and sc.C#='002'
--解法二:使用exists
select s.S#,s.Sname
from Student s,SC sc
where s.S#=sc.S# and sc.C#='001' and exists
(
    select * from SC sc2 where sc.S#=sc2.S# and sc2.C#='002'
)
复制代码

EXISTS用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值True或False。那么,这里我们来看一下in和exists的区别

  ①in 是把外表和内表作hash 连接,而exists是对外表作loop循环,每次loop循环再对内表进行查询。

  ②一直以来认为exists比in效率高的说法是不准确的

 -->如果查询的两个表大小相当,那么用in和exists差别不大。

 -->如果两个表中一个较小,一个是大表,则子查询表大的用exists,子查询表小的用in。

(7)查询学过“叶平”老师所教的所有课的同学的学号、姓名;

复制代码
--方法一
select s.S#,s.Sname 
from Student s
where s.S# in 
(
  select S# from Sc sc where sc.C# in 
  (
    select C# from Teacher t 
    inner join Course c on t.T#=c.T#
    where t.Tname='叶平'
  )
)
--方法二
select s.S#,s.Sname 
from Student s
where s.S# in 
(
    select sc.S# 
    from SC sc,Course c,Teacher t
    where c.C#=sc.C# and c.T#=t.T# and t.Tname='叶平'
    group by sc.S#
    having COUNT(sc.C#)=
    (
        select COUNT(c1.C#) 
        from Course c1,Teacher t1 
        where c1.T#=t1.T# and t1.Tname='叶平'
    )
)
复制代码

(8)查询课程编号“002”的成绩比课程编号“001”课程低的所有同学的学号、姓名;

  select s.S#,s.Sname from Student s,
  (select sc1.S#,sc1.Score from SC sc1 where sc1.C#='002') a,
  (select sc2.S#,sc2.Score from SC sc2 where sc2.C#='001') b
   where s.S#=a.S# and s.S#=b.S# and a.S#=b.S# and a.Score<b.Score

(9)查询有课程成绩小于60分的同学的学号、姓名;

 

  select s.S#,s.Sname
  from dbo.Student s
  left join dbo.Sc sc 
  on s.S#=sc.S#
  where sc.score < 60
  group by s.S#,s.Sname

 

复制代码
select s.S#,s.Sname 
from Student s
where s.S# in
(
    select distinct(sc.S#) from SC sc
    where s.S#=sc.S# and sc.Score<60
)
复制代码

(10)查询没有学全所有课的同学的学号、姓名;(可以从学全的学生中取反)

复制代码
select s.S#,s.Sname
from Student s
where s.S# not in
(
    select sc.S#  from SC sc
    group by sc.S#
    having COUNT(distinct sc.C#)= --按照学号分组计算每个学号总的课程数
    (
        select COUNT(distinct c.C#) from Course c --计算总得课程数
    )
)
复制代码

(11)查询至少有一门课与学号为“001”的同学所学相同的同学的学号和姓名;

复制代码
--方法一
select s.S#,s.Sname from dbo.Student s
where s.S# in
  (
    select distinct(sc.S#) from dbo.Sc where sc.C# 
    in(select  distinct(sc.C#)  from dbo.Sc sc where sc.S# = '001')
  )
--方法二
select distinct(s.S#),s.Sname from dbo.Student s
inner join dbo.Sc 
on s.S# =sc.S# and s.S# in
  (
    select distinct(sc.S#) from dbo.Sc where sc.C# 
    in(select  distinct(sc.C#)  from dbo.Sc sc where sc.S# = '001')
  )
--方法三
 select distinct(s.S#),s.Sname
from Student s,SC sc
where s.S#=sc.S# and sc.C# in
(
    select distinct(sc2.C#) from SC sc2
    where sc2.S#='001'
)
order by s.S# asc
复制代码

 (12)查询至少学过学号为“001”同学所有一门课的其他同学学号和姓名;(感觉跟11题有重叠)

复制代码
select distinct(s.S#),s.Sname 
from Student s,SC sc
where s.S#=sc.S# and s.S#!='001' and sc.C# in
(
    select distinct(sc2.C#) from SC sc2
    where sc2.S#='001'
)
order by s.S# asc
复制代码

(13)把“SC”表中“叶平”老师教的课的成绩都更改为此课程的平均成绩;

复制代码
update SC set Score=
(
    select AVG(score) from SC sc,Course c,Teacher t
    where sc.C#=c.C# and c.T#=t.T# and t.Tname='叶平' 
)
where C# in 
(
    select distinct(sc.C#) from SC sc,Course c,Teacher t
    where sc.C#=c.C# and c.T#=t.T# and t.Tname='叶平'
)
复制代码

查询“叶平”老师教的课

复制代码
select * from dbo.Sc sc where sc.C# in
(
    select c.C# from dbo.Teacher t 
    inner join dbo.Course c
    on t.T#= c.T# 
    where t.Tname='叶平' 
)
复制代码

 

 --(14)查询和“002”号的同学学习的课程完全相同的其他同学学号和姓名;

复制代码
select s.S#,s.Sname 
from Student s
where s.S#!='002' and s.S# in 
(
    select distinct(S#) from SC
    where C# in (select C# from SC where S#='002')
    group by S#
    having COUNT(distinct C#)=
    (
        select COUNT(distinct C#) from SC
        where S#='002'
    )
)
复制代码

(15)删除学习“叶平”老师课的SC表记录;

delete from SC where C# in
(
    select c.C# from Course c,Teacher t
    where c.T#=t.T# and t.Tname='叶平'
)

(16)向SC表中插入一些记录,这些记录要求符合以下条件:①没有上过编号“002”课程的同学学号;②插入“002”号课程的平均成绩; 

  insert into SC
  select s.S#,'002' C#,(select AVG(sc.score) from dbo.Sc sc where sc.C# = '002') score
   from dbo.Student s where s.S# not in
  (
    select distinct(sc.S#)  from dbo.Sc sc where sc.C# ='002'
  )

(17)按平均成绩从低到高显示所有学生的“语文”、“数学”、“英语”三门的课程成绩,按如下形式显示: 学生ID,语文,数学,英语,有效课程数,有效平均分;

复制代码
select t.S# as '学生ID',
(select Score from SC sc where sc.S#=t.S# and sc.C#='002') as '语文',
(select Score from SC sc where sc.S#=t.S# and sc.C#='003') as '数学',
(select Score from SC sc where sc.S#=t.S# and sc.C#='004') as '英语',
COUNT(t.C#) as '有效课程数',
AVG(t.Score) as '有效平均分'
from SC t
group by t.S#
order by AVG(t.Score)
复制代码

sql中自连接的使用

select sc2.S# as '学生ID',
(select Score from SC sc1 where sc1.S#=sc2.S# and sc1.C#='002') as '语文'
from SC sc2
group by sc2.S#

 

 

 

 

 

 

 

http://www.cnblogs.com/edisonchou/p/3878135.html

posted @ 2019-05-30 16:55  一贴灵  阅读(1153)  评论(0)    收藏  举报
学以致用,效率第一