第六天 -- 《2014-07-12 SQL进阶》2 --视图、变量、条件、循环、事务

一、下午  《02、视图》--创建和检索

1、创建视图

if exists(select * from sysobjects where name='vw_getStudentBySex')
  drop view vw_getStudentBySex
go
create view vw_getStudentBySex --这个创建语句必须是批处理的第一句
as
    --视图里面不能使用order by ,除非你同时使用了top ,
--但是我们又希望检索所有的记录所以可以用top 99.999999 percent(不用100是因为微软的bug:如果是100%就不能排序)
select top 99.99999 percent * from Student order by StudentName

--select * from grade 视图中只能创建一个select查询 --update grade --不能在视图中创建update delete 和insert go

创建视图的时候要注意:

(1)视图只包含一条select语句,不允许多条select,不允许update、insert、delete

(2)视图中不能写order by排序,除非同时使用top,如果希望检索所有记录,必须写top 99.9999 percent *

 

2、SQLServer中访问视图

(1)一般不进行增、删、改操作。(有的DBMS根本就不允许)

(2)对视图的增、删、改操作会直接影响原始的物理表。

(3)对视图的增、删、改操作仅仅局限于实际只改动单个物理表,如果操作涉及到多个表执行失败。

比如:视图V由表A和表B连接而成,删除一条视图记录肯定会失败,因为会分别删A表和B表相关记录。

更新的话,如果只更新A或B的字段,可以执行,但是如果希望同时更新A表、B表字段,就会失败。

 

 

二、下午  《03、局部变量》--《05、全局变量》

1、局部变量

(1)局部变量声明和赋值

set和select都可以为局部变量赋值。select一次可以对多个变量赋值,而set一次只能对一个。

 1 go
 2 declare @name nvarchar(50) =‘abcd’, @age int =30    
 3 set     @name='fadsfas'
 4 select  @name='ereterte' ,@age=31
 5 
 6 go
 7 
 8 --例子:查询比刘建大的学员
 9 declare @time datetime
10 select @time = (select borndate from Student where StudentName='刘健')   --如果select和set后是两个完整子查询,那么这两者无差别。
11 set @time=(select borndate from Student where StudentName='刘健')
12 
13 select * from Student where BornDate < @time

 

(2)在select检索中为变量赋值

go
declare @name nvarchar(10), @age int=20

--1、用完整子查询对变量赋值,子查询必须是返回一个值
--以下两行会报错:当没有用 EXISTS 引入子查询时,在选择列表中只能指定一个表达式。
--set    @name = (select * from Student)  
--select @name = (select * from Student)  

--以下两行会报错:子查询返回的值不止一个。当子查询跟随在 =、!=、<、<=、>、>= 之后,或子查询用作表达式时,这种情况是不允许
--set    @name = (select StudentName from Student)  --没有where筛选
--select @name = (select StudentName from Student)  

--2、如果=号右边是不完整sql语句,那么当语句返回多行一列值的时候,select会得到最后一个值
select @name = StudentName from Student  --然而set不允许这样使用
print  @name


--3、如果完整子查询返回空值,set和select都会把这个空值赋给变量
go
declare @name nvarchar(10) ='aaaaa',  @age int=20
select @name = (select Studentname from Student where StudentNo = 100)   --假设子查询返回空结果集 
print @name    --打印一个空值
print 'asfasd'


--4、如果=号右边是不完整sql语句,而且select查询没有返回任何结果值,那么selcet会保留原始拥有的默认值。因为where找了半天没select一行,也就是没执行变量赋值那一句
go
declare @name nvarchar(10) ='aaaaa',  @age int=20
select  @name = Studentname from Student where StudentNo=100   --假设查询返回空结果集
print @name    --打印默认值aaaaa
print 'asfasd'

 

2、变量使用示例

 1 --例子:查询参加最近一次“office”考试成绩最高分和最低分
 2 --分析:第一步先写好查询语句框架(最高分、最低分都是从考试成绩Result表获得,表中SubjectId指示科目id,ExamDate指示考试日期)
 3 --select MAX(StudentResult), MIN(StudentResult) from Result where SubjectId=( office的科目id ) and  ExamDate=( 最近一次office考试日期 )
 4 
 5 go
 6 declare @subjectName nvarchar(50)= 'office' --科目名称
 7 --第二步:获取科目ID
 8 declare @subjectId int --科目ID
 9 set @subjectId = (select SubjectId from Subject where SubjectName = @subjectName) --获取科目ID
10 
11 --第三步:获取最后一次考试office的时间
12 declare @time datetime  --最近一次考试时间
13 select @time = MAX(ExamDate) from Result where SubjectId = @subjectId --获取这一科目最近一次考试日期
14 
15 --第四步:把上面2~3步填入第一步填空处。
16 select MAX(StudentResult), MIN(StudentResult) from Result where SubjectId=@subjectId and ExamDate=@time
17 go

 

3、全局变量(系统变量):

全局变量必须以标记@@作为前缀,如@@version(下图中红色标记的为常用全局变量)
全局变量由系统定义和维护,我们只能读取,不能修改全局变量的值。

1、@@error与@@ROWCOUNT

前者可以用来查看sql执行是否有错(返回错误代码),后者查看多少行受影响。经常在事务中做判断条件等等使用。

2、@@ServerName与@@ServiceName

前者返回服务器名(服务器计算机名),后者返回数据库服务名(如MSSQLServer)

3、@@Identity

用于表中主键为标识列自增长,插入记录后,希望返回该主键值。注意该值根据客户端连接不同,返回各自的值(不会出现张冠李戴)

比如 :

1 insert into grade values('高三一班'); 
2 select @@identity;  --获取该会话最后一次插入数据后的自增长标识列值

如果会话并没插入数据,select @@identity  会返回NULL

 

 

 

三、下午  《06、if...else》 

 类似于C的if...else 但是大括号用begin...end代替。例子:

 1 --计算office科目平均分数并输出,如果平均分数超过60分输出成绩最高的三个学生的成绩,否则输出后三名的学生
 2 go
 3 declare @subjectName nvarchar(50) = 'office' --科目名称
 4 declare @subjectId int = (select subjectId from Subject where SubjectName= @subjectName) --科目ID
 5 declare @avg int --平均分
 6 set @avg = (select AVG(StudentResult) from Result where SubjectId=@subjectId and StudentResult is not null)
 7 if(@avg>=60)
 8   begin
 9     print '考得不错,输出前三名'
10     select top 3 * from Result where SubjectId= @subjectId order by StudentResult 
11   end
12 else
13   begin
14     print '考得不好,输出后三名'
15     select top 3 * from Result where SubjectId= @subjectId order by StudentResult desc
16   end

 

四、下午  《07、While》 --循环

 类似于C的while  但是大括号用begin...end代替。例子:

 1 --WHILE循环
 2 --可以嵌套
 3 --没有{},使用begin..end
 4 --不能使用true/false,只能使用条件表达式
 5 --如果里面只有一句就可以不使用begin..and包含
 6 --可以使用contiune/break
 7 --如果office不及格的人超过半数(考试题出难了),则给每个人增加2分,循环加,直到不及格的人数少于一半
 8 go
 9 declare @subjectName nvarchar(50)='office'--科目名称
10 declare @subjectId int =(select SubjectId from Subject where SubjectName = @subjectName) --科目ID
11 declare @classId int =(select classid from Subject where SubjectName = @subjectName) --这一科目所属的班级ID
12 declare @totalNum int  --这一科目考试总人数
13 set @totalNum = (select COUNT(*) from Student where ClassId = @classId) --需要考试这一科目的总人数
14 declare @unpassNum int =(select COUNT(*) from Result where SubjectId=@subjectId and StudentResult<60)  --这一科目考试通过的学员人数
15 while(@unpassNum>@totalNum/2) --如果不及格人数超过总人数一半
16     begin
17         update Result set StudentResult+=2 where SubjectId=@subjectId and StudentResult <= 98
18         --重新计算不及格人数
19         set @unpassNum=(select COUNT(*) from Result where SubjectId=@subjectId and StudentResult < 60)
20     end
21     
22 --也可以这样:
23 go
24 declare @subjectName nvarchar(50)='office'--科目名称
25 declare @subjectId int =(select SubjectId from Subject where SubjectName=@subjectName) --科目ID
26 declare @classId int =(select classid from Subject where SubjectName=@subjectName) --这一科目所属的班级ID
27 declare @totalNum int  --这一科目考试总人数
28 set @totalNum=(select COUNT(*) from Student where ClassId=@classId) --需要考试这一科目的总人数
29 --declare @unpassNum int =(select COUNT(*) from Result where SubjectId=@subjectId and StudentResult<60)  --这一科目考试通过的学员人数
30 while(1=1)
31     begin
32         if((select COUNT(*) from Result where SubjectId=@subjectId and StudentResult<60) >@totalNum/2)
33             update Result set StudentResult+=2 where SubjectId=@subjectId and StudentResult<=98
34         else
35             break --跳出循环
36     end

 

 1 --作业:打印如下图案,要求使用两重循环完成
 2  3 ★★
 4 ★★★
 5 ★★★★
 6 ★★★★★
 7 
 8 
 9   declare @i int =1, @j int,  @c varchar(10)     --注意1、此处@c要声明为可变字符串,可变字符串(因为下面要连接)
10   while(@i <= 5)                                 --   2、五星为Unicode,所以最好用NVarChar,或者VarChar指定长度要够用(一个字符占用字节数的区别)
11   begin 
12   set @j=1
13   set @c =''
14     while(@j <= @i)
15     begin
16         set @c +=''
17         set @j += 1
18     end
19     print @c
20     set @i += 1
21   end
 1 --上面这个作业,实际上仅仅是为了贴合要求中的两层循环。但是我们发现内层循环仅仅是为了拼接‘★’,那么如果只是输出这些五星的话,也有更简单直接的方式,如下:
 2 
 3 go
 4 declare @i int =1,@c nvarchar(5)=''
 5 while(@i <= 5)        --循环5次
 6 begin
 7     print @c          --每次打印字符串c
 8     set @i += 1       --为了5次循环
 9     set @c += ''    --每次连接一个五星
10 end

 

 

 

五、下午  《08、事务》

 

---事务的特点’:CUID
--1.C:原子性:事务不可以再分,事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行
--2.U:一致性:事务处理前后。,数据需要保持某种程度的一致
--3.I:隔离性:每一个事务是独立的,不受其它事务影响
--4.D:持久性:事务一旦提交,对数据的修改永久保留

--如何使用事务:将你执行的增加删除和修改命令包含在 事务的 开启和提交 或者 开启和回滚 之间。
--事务开启:begin transaction
--事务提交:commit transaction
--事务回滚:rollback transaction

 1 --例子:aa转1000给bb
 2 --使用事务进行转帐
 3 declare @cuowuhao int = 0 --记录执行语句过程中有可能出现的错误号
 4 begin transaction
 5 update bank set cmoney=cmoney-1000 where name='aa'
 6 set @cuowuhao=@cuowuhao+@@ERROR --只是做一个错误号的累加
 7 
 8 update bank set cmoney=cmoney+1000 where name='bb'
 9 set @cuowuhao+=@@ERROR
10 
11 if(@cuowuhao<>0) --有错误 只有全部语句执行完之后,再进行整体的判断
12   rollback transaction
13 else
14   commit transaction

 

posted on 2017-07-26 13:43  困兽斗  阅读(234)  评论(0)    收藏  举报

导航