select grade ,avg(grade) from sc group by sno;
//就会产生错误选择列表中的列 ‘sc.Grade’ 无效,因为该列没有包含在聚合函数或 GROUP BY 子句中。
//很明显呀,你是按照学号排,你把分组之后的结果和grade放在一起,你觉得符合人之常情吗,明白了没,这么通俗易懂!!!!!!
select sno from Student where Sno notin (select Sno from SC where Cno in(select Cno from Course where Cname in('计算机导论','高等数学')));
不相关子查询
子类查询的条件不依赖于父类,一般先执行子查询,然后根据子查询的结果用于父类查询的条件。
select sname from Student where Sdept in (select Sdept from Student where Sname='刘晨')
//查询和刘晨一个系的学生
//自身连接
selectfirst.sname from Student first ,Student secondwherefirst.Sdept = second.Sdept andsecond.Sname='刘晨'
//查询选修信息系统的学生信息
select sc.sno,sname from SC,Student where Cno in(select Cno from Course where Cname='信息系统') and SC.sno=Student.sno
select student.sno,sname from SC,Student,Course where Student.Sno = SC.Sno and SC. cno= Course.Cno and Cname='信息系统'
相关查询
在主查询中,每查询一条记录,需要重新做一次子查询,这种称为相关子查询。
找出每一个学生它的成绩是超过他所有选课平均成绩的学生信息
select sno,cno from SC x where grade>=(selectAVG(grade) from sc y where y.Sno = x.Sno)
//查询非计算机系中比计算机系任意一个学生年级小的学生。
select sname,sno from student where sage<any(select sage from student where sdept='cs') and sdept!='cs';
//查询非计算机系中比计算机系所有学生年级小的学生。
select sname,sno from student where sage<any(select sage from student where sdept='cs') and sdept!='cs';
带谓词(Exists)的子查询
Exists代表存在量词,带Exists的谓词子查询不返回任何数据,只产生逻辑真和逻辑假。
//连接查询
select sname from SC,Student where SC.Sno = Student.Sno and Cno=1;
//谓词查询
select sname from Student whereexists(select * from sc where SC.sno = student.sno and cno=1)
//他的执行过程,先从student表中每一条记录拿学号和对应的sc.sno并且cno =1,如果符合条件将student中的sname保存到结果集。
//如果内层查询结果非空,则外层where子句返回真值,否则返回假值。
//由于exists引出的子查询,其目标列通常用*表示,因为exists子查询不返回真值,给出列名无意义。
//与exist对应的是no exists(不存在)
select sname from Student wherenoexists(select * from sc where SC.sno = student.sno and cno=1)
查询同时选修“计算机导论”或者 “高等数学”的学生
思考:这两门课没有一门是他没有选修的。
select sno,sname from Student wherenotexists (select * from Course where Cname in ('计算机导论','高等数学') andnotexists (select * from SC where Sno =Student.Sno and Cno = Course.cno));
集合查询
主要包括:并(union)、交(intersect)、差(except)。
//其实我并不明白存在的意义,明明可以用or、and处理,也许我还没发现其中奥妙。 在集合操作union会自动去除重复的,而or是所有的包括重复,在集合中如果不要重复union all
差运算就是返回除去条件后的所有结果集。
//查询选修课程1或者课程2的学生
select sno from SC where cno=1unionselect sno from SC where Cno =2select sno from SC where Cno =1or Cno =2;
基于派生表的查询
子查询可以在from子句出现,这时子查询生成临时表,成为主查询对象。
//查询超过他选修所有课程成绩平均值的学生select sc.sno,cno from SC ,(select sno,AVG(grade) from SC groupby(sno)) as avg_1(sno,avg_grade)
where avg_1.sno = SC.Sno and grade>avg_1.avg_grade
//该执行过程,在执行到from后面将结果集保存在临时表中,然后在进行条件比较,最终返回符合的结果。//*如果子查询中没有聚合函数,或者计算式,可以无需指定别名*
SELECT 字段 FROM 视图名
//这里字段如果你创建视图给了字段名,就直接用,不然还是子查询的select后面的属性列名。
视图的检查
createview view3 asselect sno,sname,sage,sdept from Student where sdept ='信息系'withcheckoption;
//在后面对视图的操作中,增删改,读必须有条件就是部门是信息系,最简单你不能往视图中加一个别的系的,这个还懂吗!!!!!!!!!!!
视图上的建立
建立选修c01并且grade>90视图
createview view5 asselect sname from view4 where grade >90;
//这个视图就是基于view4之上,view4中有grade字段。
虚拟列视图
创建学生的姓名,出生日期的视图
该查询中包含计算公式,所以必须创建一个新的列,所以整个查询的都要显示的赋一个名字。
createview view6(sname,sbirth) asselect sname,2017-sage from Student;
基于分组的视图
查询每一个学生多门选修的平均成绩的视图
该查询中包含聚合函数,所以要显示指定每一个属性列。
createview view7 (sno,savg) asselect sno,AVG(grade) from SC groupby Sno;
删除视图
Dropview <视图名> [CASCADE]
如果该视图上海导出其他视图,那么需要加上级联操作,这样才可以将级联的视图一起删除。
注意:删除视图,只是从数据字典中删除,并不影响基本本的数据
视图的查询
在view1中查询年纪小于22的学生信息
select * from view1 where sage <22;//你可以利用视图中属性列名去做你需要的条件。
视图是可以和基本表进行连接的
select grade from sc,view4 where view4.sno =SC.Sno;
createtrigger <触发器名> on {table|view}
[with encryption] for {after|instead of} {insert|update|delete}
as
sql_statement
//触发器激活后所作的操作,例如检查、回滚,插入,删除
触发器after、instead of区别
AFTER:触发发生在SQL操作后,若发生错误,可利用回滚恢复原数据。
INSTEAD OF:触发发生在SQL操作前,且如何操作由触发器操作来实现。
INSTEAD OF 触发器的主要优点是可以使不能更新的视图支持更新。(为什么说INSTEAD OF对于视图的更新有很大作用,首先我们都知道视图是虚表,不可以对基本表进行修改,所以在视图上修改就是不可能,那么你用触发器的INSTEAD OF,就是代替执行,可以转化为对基本表的执行)基于多个基表的视图必须使用 INSTEAD OF 触发器来支持引用多个表中数据的插入、更新和删除操作。
createtrigger courese_trigger on course forupdate ,insertasif((selectcount(*) from course ,inserted where course.cname=inserted.cname)>1)//sql语言的编写,后面会讲,你看看吧。
//这个inserted表,会保存你插入的信息,从这个内存表中找到呢要插入的cname,来判断表中要没有此过程。
begin
print '存在相同的课程名,操作无法执行'//打印出错信息
rollbacktransaction//事务回滚,不做任何操作
end
创建触发器 ,学生选修同一门课程不能超过5人
createtrigger sc_trigger on sc forinsertasif((selectcount(*) from sc,inserted where sc.cno = inserted.cno)>5)
begin
print '该课程选修人数超过5人,该操作无法执行'rollbacktransaction//注意对于条件约束检查,如果不满足一定要执行回滚事件,不然该操作还是会执行。
end
CREATETRIGGER [CHECK_NUM] ON [ORDER] //在写该题有个注意点,就是sqlserver如果你自己定义和保留字一样,那么需要加[]以区分,注意以下。
FORINSERT, UPDATEASIFUPDATE(NUM)//如果你这样指定的话,只有修改num列的时候才会触发该触发器
BEGIN
//*由该例子我们可以看到if后面的条件我们要删除转化为存在、不存在、count(*)的比较*
IFNOTEXISTS(
SELECT * FROM INSERTED ,CUSTOMER,CUSTOMERLEVEL
WHERE INSERTED.CID=CUSTOMER.CID AND
CUSTOMERLEVEL.CLEVEL=CUSTOMER.CLEVEL AND
NUM NOT BETWEEN CUSTOMERLEVEL .NUMDOWN AND
CUSTOMERLEVEL .NUMUP )
//该实例判断也可这样
/*if((selectcount(*) from customerlevel,inserted ,customer,[order] where inserted.cid = customer.cid and customer.clevel= customerlevel.clevel and inserted.num between numdown and numup)<1)*/
BEGIN
PRINT '订购数量违反了客户的限额!'ROLLBACKENDEND
基于instead of 的触发器
createview view8 asselect sno,sname from student//创建视图
select * from view8;createtrigger studnet_trigger on view8
instead ofinsert//在插入视图前操作
asbegininsertinto Student (Sno,sname)values ((select sno from inserted),(select sname from inserted))//通过这个可以看出,触发器还是转化对基本表的操作
endinsertinto view8(sno,sname) values('88888','枪仔')//往视图中插入数据,和往表中插入数据一致。
createprocedure student1
asbeginselectdistinct sname,sc.cno,grade from student,sc,course where student.sno = sc.sno and sc.cno = course.cno and sdept='计算机系'endexec student1//执行存储过程
创建带参数的存储过程
createprocedure student2(@sdept char(20))//里面变量,这里不加declare可能定义存储过程的底层已经有了
asbeginselectdistinct sname,sc.cno,grade from student,sc,course where student.sno = sc.sno and sc.cno = course.cno and sdept=@sdept//里面赋值,这里不加set可能定义存储过程的底层已经有了
endexec student2 '数学系'//传入真正执行的参数
创建参数有默认值的存储过程
createprocedure student3(@sdept char(20)='数学系')
asbeginselectdistinct sname,sc.cno,grade from student,sc,course where student.sno = sc.sno and sc.cno = course.cno and sdept=@sdept
endexec student3
创建输出存储过程的值
createprocedure produce1 (@cname varchar(20),@avgintoutput)//创建一个输出参数
asbeginselect @avg = avg(grade) from sc,course where sc.cno = course.cno and cname=@cname
//将执行结果的值赋值给输出参数
enddeclare @return_avg int//申明要打印的参数
exec produce1 'vb' ,@return_avg output//后面的语句执行会将存储过程的输出值赋值给定义的变量然后打印,output不能少。
print @return_avg
存储过程稍微复杂例子
createprocedure proceduce2 (@sno char(7),@cno char(10))
asbeginif((selectcount(*) from sc where sc.cno = @cno)>5)
return 0elsebeginif((selectCOUNT(*) from SC where Sno=@sno)>3)
return -1//可以使用return标志执行结束
elseinsertinto SC(Sno,cno) values(@sno,@cno)
return 1endend