SQL初级第三课(下)
我们续用第三课(上)的表
辅助表
Student Course Score Teacher
Sno Cno Sno Tno
Sname Cname Cno Tname
Ssex Tno Degree Tsex
Sbirthday Tbirthday
class Prof
Depart
Having
Having:在分组的基础进一步筛选,没有group by子句时,不能使用Having子句,因为having字句是针对group by子句的
例:查询score中选学多门课程的同学中分数为非最高分成绩的记录。
这里有两个筛选条件比较绕,选多门课程的同学和非最高分。首先我想到的是查询语句中应该有 count(*)>1 和 not in (最高分)
选多门课程意味着sno重复出现至少两次,那么我们就应该按照sno分组。
按照题意:select * from score where sno in (select sno from group by sno having count(*)>1) --括号里是以sno列分组后行数大于1的sno
这里返回的是学生号码sno,按照得到的学生号码再score表里对应写出信息,我们就得到了选多门课程的成绩信息。
那么我们要在这个基础上再筛选出最高分的成绩Max(degree)那么,
select * from score where sno in (select sno from group by sno having count(*)>1)
and
degree not in(select max(degree) from score group by sno having count(*)>1 )--括号里子查询返回了一个被两个人或以上选修的课程的最高分。我们用去除这个最高分剩下的成绩就是非最高分得的记录。
相关子查询
还是关于这个题,查询除了每门课最高分之外的其他学生信息。
仿佛可以这样写: select * from score where degree not in (select max(degree) from score group by cno )
这个语句乍一看仿佛是对的因为子查询括号里可以得到 根据课程号码cno分组的最高分,但问题就出在这,这个值根据课程号码cno分组多少来得到多少个值并
返回。因为是现分组再计算出最大值,加入有其它组的分数与其中一组的最高分相等,那么这个分数也将被删除,因为
select * from score where degree not in()只执行将得出的几个值删除。
思路:我们设两个score表a,b内容一样的表score,但是他们是两个不同的表,那么我们通过子查询在score b中把cno列分组,然后在分好的组中查找degree的每组最大值,得出数据。
步骤1: select * from score where degree () --括号里应写入每门课的最高分;
步骤2: select * from score where degree not in (select max(degree) from score group by cno) --按照cno分组求出最高分,然后not in 去除,但是这样如果其他课的分数跟某门课的最高分一样,这样他一样会被错误去除,为了避免我们要有个having条件限制;
步骤3: select* from score a where degree not in (select max(degree) from score b group by cno having b.cno=a.cno);
--这样我们按照cno求出每门课最高分,score a和score b是内容与score相同的两个不同子表,只有score b表求出的最高分的b.cno与a.cno相同时这样我们才能够在
score a表中删除degree;
再练一个,例:查询成绩比该课程平均成绩低的同学的成绩表。
先分解:查询成绩表
步骤1: select * from score
比平均分低
步骤2: select * from score degree <(select avg(degree) from score) --求出课程平均分,但是求的是所有课程平均分,但这次我们不分组了
直接带入条件,where筛选循环依次带入来查找
步骤3:select * from score a degree <(select avg(degree) from score b where b.cno=a.cno) --根据课程依次带入cno,然后根据cno求出平均分,
在b表里求出的这个平均分,在b.cno=a.cno相同的时候可以影响a表,但是啊a,b表内容一样所以不影响结果。
第一种方法是先分组,group by-having
第二种方法是循环,where
如果这两种方法对于你都不好理解,那我我还有第三种方法--背过样子,做时判断!
首先判断这个题是否用到相关子查询,然后格式很简单 设a,b表然按照什么分组你就 where a. 分组=b.分组。
要判断是否是相关子查询要满足几个必要的条件;
1:要求一项内容但是按照表的其他条件分组。
2:一般会有聚合函数配合使用。
无论这3种方法掌握哪一种都一样吃饭。
------------------------------------------------------------------我是华丽的分割线------------------------------------------------------------------
连结
例:查询所有“女”教师和“女”同学的name、sex和birthday;
select sname,ssex,sbirthday from Student where ssex='女'
union
select tname,tsex,tbirthday from Teacher where Tsex='女'
--用union把两个表中查询的数据连结,要注意被union的两个表要包括相同的查询列数,查询的数据类型。第一个表先显示,按照第一个表的列名显示
------------------------------------------------------------------ 我是华丽的分割线 ------------------------------------------------------------------
模糊查询
查询Student表中不姓“王”的同学记录;
select * from student where sname not like '王%'
--用like 和 %表示模糊查询,%代表无限位其他内容
------------------------------------------------------------------ 我是华丽的分割线 ------------------------------------------------------------------
例:查询Student表中每个学生的姓名和年龄。
select sname,year(getdate())-year(sbirthday) as 年龄 from student;--year()-括号里是一个datetime类型的列,然后截取年份返回一个int类型的值;
详情请访问 CSDN或MSDN
常见命令
Left
select left('abcder',2) 总左往右截取2个字符
right 从右往左
select LOWER('ABC') 转换大小写
select UPPER('abc')
select LEN('abcd') 返回int 类型值 长度多少
select LTRIM (' fdfc')去左空格
select RTRIM(' sdf sfsd ')
print substring('abdfregsfdfsdfsd',1,2) 索引从1开始 从第2个 截取几个
select replace('dsfgregwgfsfd','f','popopopopo') 目标数据源,你在这个目标里找什么,替换成什么
select REPLICATE('傻逼',20) 复制,指定内容 复制几次
print str(123.46,5,1) 转换字符串,目标,显示几位,小数点几位
select PATINDEX('%123%','adf215123dfgergre25') 返回目标在字符串中的索引
select STUFF ('sdfsdfsdfsdf'4,2,'zzzzzzz') 插入zzzzzzzz在第4位还得删除后两位
转换函数 cast convert
select cast ('123' as int) +12
select cast (123 as varchar(50))+'123'
select CONVERT(int,123)+13
------------------------------------------------------------------ 我是华丽的分割线 ------------------------------------------------------------------
小结:
*Having要跟group by连用,一般加上一个聚合函数作为条件;
*通过联系培养思维习惯,遇到复杂的题要分解,都是白话文,先打出最终输出——根据筛选条件写出代码用()设为子查询——连接使用;
*当子查询跟随在 =、!=、<、<=、>、>= 之后, 子查询的返回值只能是一个, 否则应在外层where子句中用一个in限定符,即要返回多个值,要用in或者not in;
*SQL有自己的脾气,表为内嵌,命令选中执行,建表顺序,先主键再外键;如果有修改先执行删除重新insert;
*字符串别忘了用 ''引用起来;