一个项目涉及到的50个Sql语句(oracle版)
刚自学完oracle的基础,所以就想找一些SQL问题来练练手,所以就选择了这个50sql语句,因为找到的版本不是oracle的,所以尝试着用oracle来实现.
这篇博文主要是想记录在做这50道题的时候的理解,答案跟网上的差不多.现在就把这二天刚做的发上来.
4个表的数据
student表
SQL> select *From student;
SID SNAME SAGE SSEX
----------
-------------------- ---------- ----------
01 a
20 女
02 b 20 女
03 c
20 女
04 d 20 男
05
e 20 男
06 f
21 女
07 g 23 男
08 h
19 女
已选择8行。
teacher表
SQL> select *From teacher;
TID TNAME
---------- --------------------
01 a
02
b
03 c
course表
SQL> select *From course;
CID CNAME TID
---------- --------------------
----------
01 a 01
02 b
02
03 c 03
sc表
SQL> select *From sc;
SID CID SCORE
---------- ---------- ----------
01
01 39
01 02 89
01 03
69
02 01 74
02 02
65
02 03 89
03 01
68
03 02 87
03 03 75
04
01 57
04 02 73
SID CID SCORE
---------- ---------- ----------
04
03 97
05 01 84
05 02
84
05 03 31
06 01
82
06 02 71
06 03
91
07 01 39
07 03 82
已选择20行。
创建在wcb用户下
1、查询"01"课程比"02"课程成绩高的学生的信息及课程分数
这道题难就难在,需要保证在同一个sid下,如何查询c1分数>c2分数的记录
我想不出来
最后是这么解出来的
1)这种查询是针对同时存在01和02课程的情况
SQL> select a.*,b.score 课程1的分数,c.score 课程2的分数
from student a,sc b,sc c
where a.sid=b.sid and a.sid=c.sid and b.cid=‘01‘ and
c.cid=‘02‘ and b.score>c.score;
SID SNAME SAGE SSEX 课程1的分数
课程2的分数
---------- -------------------- ---------- ---------- -----------
-----------
02 b 20 女 74
65
06 f 21 女 82
71
精秒之处,在查询字段里,创建了两个同一个表的字段,这样就解决了如何进行c1与c2比较的问题,我最开始是这样写
select *from sc
where (select score from sc where cid=‘01‘) > (select score from sc where
cid=‘02‘) 结果出错,说单行子查询返
回多行两个同一个表的字段,这样就可以用来逐行比较同表数据,比如说它这一句
b.score>c.score
然后用a.sid=b.sid and a.sid=c.sid 它这样写就能确定c1与c2都来自同一个sid,因为其实还可以再写一个等价关系,如
b.sid=c.sid 只是这样没
必要,因为它这样写,等价关系就是这样 b.sid=a.sid=c.sid 即b.sid=c.sid拉.
而b.cid=‘01‘ and c.cid=‘02‘ 相当于两个查询语句 select *From sc where cid=‘01‘ select
*From sc where cid=‘02‘ 然后后面再接句
b.score>c.score
2)针对同时存在"01"课程和"02"课程的情况和存在"01"课程但可能不存在"02"课程的情况(不存在时显示为null)(以下存在相同内容时不再解释)
SQL> select a.*,b.score 课程01的分数,c.score 课程02的分数 from student a
left
join sc b on a.sid=b.sid and b.cid=‘01‘
left join sc c on a.sid=c.sid
and c.cid=‘02‘
where b.score>nvl(c.score,0);
SID SNAME SAGE SSEX 课程01的分数
课程02的分数
---------- -------------------- ---------- ---------- ------------
------------
02 b 20 女
74 65
06 f 21 女
82 71
注 我在想 这些连接(如内连接,外连接,from后面跟一个子查询)跟条件有什么关系,是我们连接查出来的数据,然后再从这里面筛选符合条件的数据,是这
样吗?应该是的,就像上面这个例子,我表1结合表2,表3查出来的数据,再交给条件去判断,如果有遇到字段值为空的,就转为0,再判断是否大于,而连接呢,
又不是一般的查询,而是它内部也加了一个条件,筛选掉了一些数据
!!!!!!!!!!
注2:
这道题的解题思路就是,找出一个学生的两个课程成绩,如果成绩为空,则转化为0
转化为0,可以用nvl
找出两个成绩的,创建2个同类型(即SC)的字段,用左连接,
a.sid = b.sid 和a.sid = c.sid 因为它是一条一条的查的,所以在查的时候,它会先拿
a.sid去跟b表的数据比较,找到一条,再拿a.sid去跟c表的数据比较,找到一条,因为是拿同一个a.sid去比较的,所以可以保证是同一个学生的两个课程成
绩,然后b.cid=‘01‘ 跟c.cid=‘02‘则是限定那门课程
假如按上面说的,课程号为02的不存在,则第二条左查询的条件就不成立,这时,就不会显示c的任何数据,但是它还在,只是为空而已,到了where那里,当发
现c为空后,就把它转为0,也就是说,虽然左连接,右连接啊,这些,即使不符合条件,它也会存在,只是值都为空而已.
!!!!!!!!!!!!!
Ok,上面那个注是我的一个个人理解,现在说说2)这个例子,有一个疑问,就是为什么要用左连接呢?用左连接的好处,在于当有一个条件不成立的时候,左边
的字段可以照常显示,比如说字段sid为1的它的cid没有02的记录,但是我还是可以显示sid为1的这条记录,为什么呢,因为也许它有个cid为01的记录,这
样的话,因为是要比较cid为1>cid为2的数据,这样的话,没有cid为2的,我们可以当做0,也就是说,虽然sid为1的这条记录,它没有cid为2的记录,但是它
有cid为1的记录,所有符合我们的条件,就应该把它显示出来
这就是左连接跟右连接跟全连接的好处了吧,不放过任何一条符合条件的记录
为了验证我上面这句话,我插了一条记录,没有cid为02,但是有cid为01的,sid为07的记录
1 select a.*,b.score 课程01的分数,c.score 课程02的分数 from student a
2 left
join sc b on a.sid=b.sid and b.cid=‘01‘
3 left join sc c on a.sid=c.sid
and c.cid=‘02‘
4* where b.score>nvl(c.score,0)
SQL> /
SID SNAME SAGE SSEX 课程01的分数
课程02的分数
---------- -------------------- ---------- ---------- ------------
------------
02 b 20 女
74 65
06 f 21 女
82 71
07 g 23 男
39
总结
这道题学到什么呢?
1)就是同表下同字段不同值所关联的另外某个字段值的比较应该如何进行比较的问题(如cid=01的成绩跟cid=02的成绩进行比较)
2)就是真正理解了左连接这些连接,怎么解释才最容易理解呢?这样说可以吗?就是表1跟表2
,我用连接,可以得到两个表符合条件的那部分数据,但
是同时,左表或者右表不符合条件的数据也可以得到,这时候,如果需要对两个表的值大小进行比较,一些数据符合条件,但是它的值比较特殊(比如说它为
值为null,但是可以把它当做0),没用连接,就容易被筛选掉,用连接的话,就不怕被筛选掉,而是可以将特殊值转化为可比较值,从而得到最精确的结果
2) 查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩
SQL> select
a.sid,a.sname,cast(avg(b.score) as decimal(18,2)) avg_score
2 from student
a,sc b where a.sid=b.sid
3 group by a.sid,a.sname
4 having
cast(avg(b.score) as decimal(18,2)) >=60
5 order by a.sid;
SID SNAME AVG_SCORE
---------- --------------------
----------
01 a 65.67
02 b
76
03 c 76.67
04
d 75.67
05 e
66.33
06 f 81.33
07 g
60.5
已选择7行。
注:cast是用来转换数据类型的,decimal是个数据类型,类似于number
这道题学到的东西就是知道了having的作用
having是在分组后再进行过滤,也就是说可以再加个条件,这个条件,注意是可以使用分组函数的,比如说这句 having cast(avg(b.score
as
decimal(18,2)) >=60
我们在where是不可以用分组函数的来判断的,那为什么having可以呢?
因为在分组查询后,得到的数据是a.sid,a.sname,avg(score)
这时avg(score)已经是一个普通字段了,自然可以用来查询了.这可不可以看做是一个处
理组函数的思路,就是先把它转化成普通字段,再进行判断
3) 查询李姓老师的数量
SQL> select count(tname) from teacher where tname like ‘a%‘;
COUNT(TNAME)
------------
3
4)查询上过a老师课的同学信息
1 select distinct a.* from student a,sc b,course
c,teacher t
2 where a.sid=b.sid and b.cid=c.cid and c.tid=t.tid and
t.tname=‘a‘
3* order by a.sid
SQL> /
SID SNAME SAGE SSEX
----------
-------------------- ---------- ----------
02 b
20 女
03 c 20 女
04 d
20 男
05 e 20 男
06
f 21 女
07 g
23 男
已选择6行。
5)没上过a老师课的同学
SQL>select student.* from student where sid not in
(select distinct a.sid from student a,sc b,course c,teacher t
where a.sid=b.sid and b.cid=c.cid and c.tid=t.tid and t.tname=‘a‘)
order
by sid;
SID SNAME SAGE SSEX
----------
-------------------- ---------- ----------
01 a
20 女
08 h 19 女
这道题学到了not in
6)查询学过编号为"01"并且也学过编号为"02"的课程的同学的信息 (做到这个实验我就明白,在筛选数据的时候,是一条一条筛选,每一条都要符合
where后面的这些条件)
SQL>select a.* from student a,sc b,sc c where
a.sid=b.sid and a.sid=c.sid and b.cid=‘02‘ and c.cid=‘01‘
SID SNAME SAGE SSEX
----------
-------------------- ---------- ----------
02 b
20 女
03 c 20 女
04 d
20 男
05 e 20 男
06
f 21 女
6)查询学过编号为"01"并且但没学过编号为"02"的课程的同学的信息
SQL> select Student.* from
Student , SC where Student.Sid = SC.Sid and SC.Cid =‘01‘ and Student.Sid not in
(Select
SC_2.Sid from SC SC_2 where SC_2.Sid = SC.Sid and SC_2.Cid = ‘02‘)
order by Student.Sid;
SID SNAME SAGE SSEX
----------
-------------------- ---------- ----------
07 g
23 男
这道题,学到的是,一种思维的转变,要求是没学过编号为02的课程的同学,我当时做这道题的时候,思路没转过来,想的是怎么在sc表里加条件,使得既符合
学过编号为01,又没学过02的,后来还是没解出来,看了答案,才知道,原来可以这么解,把学过02课程的同学的ID找出来,然后只要ID不在这些ID的,就是没
学过02,啊,有时候,真的转变下思维,真的很简单,但我在下次再遇到这些问题时?我能转变过来吗?
7)查询没有学全所有课程的同学的id
我是这样实现的
SQL>select a.sid from student a,sc b
where a.sid=b.sid
2 group by a.sid
3 having count(b.cid) < (select
count(cid) from course)
SID
----------
07