数据库操作 总结

本人录制技术视频地址:https://edu.csdn.net/lecturer/1899 欢迎观看。

1.数据库中关于字段加值的处理

update T_Teacher set tSalary=tSalary+2000 where tSex='true';

这种情况,必须写成 tSalary = tSalary + 2000, 因为是将数据库中原来的值进行了修改。

select tSalary+2000 ,tName from T_Teacher

而这种情况,是取得数据库中的数据,并将tSalary值加2000,显示出来,而数据库中原来的值并没有被改变 

 

2.备份表时,约束不会备份 

1、  将数据和结构备份了下来 

select * into 新表名 from 源表名

2、  将表的结构备份了下来 

select * into 新表 from 源表 where 1>2


3.drop,delete与truncate的区别:

drop是将整个表删除了(表的内容与表的结构都被删除了)

delete是将表的内容删除了,表的结构还在,当下次再插入数据的时候,id从上次最大的id+1开始算起

truncate也是将表的内容删除了,表的结构还在,但下次再插入数据的时候,id会从1开始重新计算。但是,它不会将数据记录到日志文件,一旦删除,就无法恢复了(慎用)! 


4.表中列的操作修改表(修改表的同时不能添加约束,修改完成之后可以添加约束):

删除一列:  alter table 表名 drop column 列名

增加一列:  alter table 表名 add 列名 类型

修改数据类型:  alter table 表名 alter column 列名 类型 


5.数据库中的类型转化:

cast(expression as date_type) 或者 convert(date_type,expression) 


6.DISTINCT是对整个结果集进行数据重复抑制,而不是针对每一列

如select distinct FDepartment,FSubCompany from T_Employe是指当FDepartment,FSubCompany两个字段的内容完全相同时,才一致;有一列相同也没有关系。


7.UNION使用的两个基本原则:1、每个结果集必须有相同的列数。2、每个结果集的列必须类型相容。

其中UNION将两表合并,并且没有重复的行出现,而UNION ALL是直接将两表合并,不考虑重复问题。

例:查询每位正式员工的信息,包括工号,工资,并且在最后一行加上所有员工工资合计

select FNumber ,FSalary from T_Employee UNION select '工资合计',sum(FSalary) from T_Employee


8.row_number()函数可以计算每一行数据在结果集中的行号(从1开始计数)

用法:row_number() over(排序规则),如下列,可以直接得到按工资降序排列的所有序号:

select ROW_NUMBER() over(order by FSalary desc),FNumber,FName,FSalary,FAge from T_Employee

row_number()不能用在where子句中!

Example:查询工资按降序排列的第6到第8名的具体情况。

Method One:(子查询)

select top 3 * from T_Employee where FNumber not in
(select top 5 FNumber from T_Employee order by FSalary desc )
order by FSalary desc

Method Two: (使用row_number(),推荐)

select * from
(select *,ROW_NUMBER() over(order by FSalary desc) as rownum from T_Employee) as a
where a.rownum>=6 and a.rownum<=8


9.isnull函数的使用(将FName为null的地方用佚名取代)

select isnull(FName,'佚名') as 姓名 from T_Employee   如果FName是null,就用'佚名'替代,如果不是空,就直接取FName的值 

 

10.Group by 与 Order by

1、没有出现在group by 子句中的列是不能放到select语句后的列名列表中的(聚合函数除外)

2、聚合函数是不可以出现在where子句中的,只能在group by语句后,把聚合函数放在having子句中

3、where是对原始的数据进行过滤,having是对分组以后的数据进行过滤的

4、当出现group by 和order by混合使用时,一般先分组再排序 


11.时间函数

1、得到当前日期: 

select CONVERT(varchar(50),GETDATE(),101) as CurrentDay

如 结果:06/05/2011

2、得到当前时间 

select CONVERT(varchar(50),GETDATE(),108) as CurrentTime

如 结果:20:17:31 

3、dateadd 

select FBirthday,DATEADD(YEAR,3,FBirthday) as threeyrs,
DATEADD(QUARTER,20,FBirthday) as ttqutrs, DATEADD(MONTH,68,FBirthday) as sxtmonths, DATEADD(WEEK,-1000,FBirthday) as thweeik from T_Person

4、datediff

select FRegDay,FBirthday,DATEDIFF(WEEK,FBirthday,FRegDay) from T_Person

5、datepart,返回日期的指定格式

select FBirthday,datepart(WEEKDAY,FBirthday),FRegDay,datepart(WEEKDAY,FRegDay) from T_Person

12.Case函数 

1、如下表(条件是离散值的情况)


输出下表形式的格式:


select FName, (
case [Level] --Level是数据库中的关键字,用它作为字段的时候,要用[]括起来 when 1 then '普通会员'
when 2 then '高级会员'
when 3 then 'VIP'
end
) as 会员级别
from T_Level

2、条件是在一个范围的情况 

select FName,
(
case
when FSalary<2000 then 'Lower'
when FSalary>=2000 and FSalary<=5000 then 'Just soso' else 'Upper'
end
) as 收入水平 from T_Employee

3、表内容: 


输出下表形式的格式:


select number, (
case
when amount>=0 then amount else 0 end
) as 收入, (
case
when amount<0 then ABS(amount) else 0 end
) as 支出 from T_Amount

4、表内容:


输出下表形式的格式:


select Name, sum
(
case Score
when '胜' then 1 else 0 end
) as 胜, sum
(
case Score
when '负' then 1 else 0 end
) as 负
from T_Compare group by Name

5、表内容:


输出下表形式的格式:


select id, sum
(
case 科目
when '语文' then 成绩 else 0 end
) as 语文, sum
(
case 科目
when '数学' then 成绩 else 0 end
) as 数学, sum
(
case 科目
when '英语' then 成绩 else 0 end
) as 英语 from T_Class group by id

13. 表连接

1、内连接--常用!

--将学生表与学生成绩表联合起来(以学生的id作为连接桥梁)输出格式如下: 学生姓名、性别、年龄、班级、英语成绩、数学成绩 

select st.sname as 学生姓名,
(
--将0,1 数字表示的性别信息,用男、女代替
case st.sgender
when 0 then '女' else '男'
end
) as 性别,
st.sage as 年龄, --使用子查询实现 (
select cname from T_Class201219 where cid=st.sclass ) as 班级,
--表连接实现
sc.scEnglish as 英语成绩,
sc.scMath as 数学成绩
from T_Student201219 as st [inner] join T_Score201219 as sc on st.sid=sc.scStudent

//注:输出结果并不是所有学生的信息,因为有的学生在T_Score201219表中都没有记录(为null),所以只能连接有记录的。 

2、左连接

显示所有学生的信息,学生在T_Score201219表中没有记录的,成绩项全用null代替 

select st.sid,st.sName,sc.scEnglish,sc.scMath
from T_Student201219 as st left join T_Score201219 as sc on st.sid=sc.scStudent

同理:右连接,即学生在T_Student201219表中没有记录的,学生信息项全用null代替


14.综合例子1:

创建一张表,记录电话呼叫员的工作流水,记录呼叫员编号、对方号码、通话开始时间、通话结束时

间。建表、插数据等最后都自己写SQL语句。 

CREATE TABLE [CallRecords] (
[Id] [int] NOT NULL identity(1,1),
[CallerNumber] [nvarchar](50), --三位数字,呼叫中心员工编号(工号) [TelNum] [varchar](50),
[StartDateTime] [datetime] NULL,
[EndDateTime] [datetime] NULL --结束时间要大于开始时间,默认当前时间
)
--主键约束
alter table [CallRecords]
add constraint PK_CallRecords primary key(id)
--检查约束
alter table [CallRecords]
add constraint CK_CallRecords check(CallerNumber like '[0-9][0-9][0-9]') alter table [CallRecords]
add constraint CK_CallRecords_EndDateTime check(EndDateTime > StartDateTime)
--默认约束
alter table [CallRecords]
add constraint DF_CallRecords default(getdate()) for EndDateTime
INSERT [dbo].[CallRecords] ([CallerNumber], [TelNum], [StartDateTime], [EndDateTime]) VALUES ('001', '0208888888', CAST(0x00009DAF00A4CB80 AS DateTime), CAST(0x00009DAF00A62E94 AS DateTime));
INSERT [dbo].[CallRecords] ([CallerNumber], [TelNum], [StartDateTime], [EndDateTime]) VALUES ('001', '0208888888', CAST(0x00009DB000D63BC0 AS DateTime), CAST(0x00009DB000D68DC8 AS DateTime));
INSERT [dbo].[CallRecords] ([CallerNumber], [TelNum], [StartDateTime], [EndDateTime]) VALUES ('001', '89898989', CAST(0x00009DB000E85C60 AS DateTime), CAST(0x00009DB000E92F50 AS DateTime));
INSERT [dbo].[CallRecords] ([CallerNumber], [TelNum], [StartDateTime], [EndDateTime]) VALUES ('002', '98987676', CAST(0x00009DB2015BB7A0 AS DateTime), CAST(0x00009DB2015C4DA0 AS DateTime));
INSERT [dbo].[CallRecords] ([CallerNumber], [TelNum], [StartDateTime], [EndDateTime]) VALUES ('002', '02188839389', CAST(0x00009DA4014C9C70 AS DateTime), CAST(0x00009DA4014E0308
AS DateTime));
INSERT [dbo].[CallRecords] ([CallerNumber], [TelNum], [StartDateTime], [EndDateTime]) VALUES ('001', '767676766', CAST(0x00009DB400DAA0C0 AS DateTime), CAST(0x00009DB400DD5FE0 AS DateTime));
INSERT [dbo].[CallRecords] ([CallerNumber], [TelNum], [StartDateTime], [EndDateTime]) VALUES ('003', '0227864656', CAST(0x00009DB200B9AB40 AS DateTime), CAST(0x00009DB200B9FC1C AS DateTime));
INSERT [dbo].[CallRecords] ([CallerNumber], [TelNum], [StartDateTime], [EndDateTime]) VALUES ('003', '676765777', CAST(0x00009DB8014042B8 AS DateTime), CAST(0x00009DB80141804C AS DateTime));
INSERT [dbo].[CallRecords] ([CallerNumber], [TelNum], [StartDateTime], [EndDateTime]) VALUES ('001', '89977653', CAST(0x00009D9A00FB9898 AS DateTime), CAST(0x00009D9A00FE6118 AS DateTime));
INSERT [dbo].[CallRecords] ([CallerNumber], [TelNum], [StartDateTime], [EndDateTime]) VALUES ('004', '400400400', CAST(0x00009D9A00FB9898 AS DateTime), CAST(0x00009D9A00FE6118 AS DateTime));

要求:
1、输出所有数据中通话时间最长的5条记录

2、输出所有数据中拨打长途号码(对方号码以0开头)的总时长

3、输出本月通话总时长最多的前三个呼叫员的编号

4、输出所有数据的拨号流水,并且在最后一行添加总呼叫次数

1)记录呼叫员编号、对方号码、通话时长

2)......

3)汇总【市内号码总时长】【长途号码总时长】 

Answer 1.

select top 5 * from CallRecords order by DATEDIFF(S,StartDateTime,EndDateTime) desc

Answer 2.

select SUM(DATEDIFF(S,StartDateTime,EndDateTime)) from CallRecords where TelNUm like '0%'

Answer 3.

select CallerNumber from CallRecords
where convert(int,datepart(month,StartDateTime))=7 --表示7月份 group by CallerNumber
order by SUM(DATEDIFF(S,StartDateTime,EndDateTime)) desc

Answer 4.

select CallerNumber as 呼叫员编号,TelNum as 对方号 码,DATEDIFF(s,StartDateTime,EndDateTime) as 通话时长
from CallRecords union
select '汇总', convert( varchar(50),
(
select SUM(DATEDIFF(s,StartDateTime,EndDateTime)) from CallRecords
where TelNum not like '0%'
) ),
(
select SUM(DATEDIFF(s,StartDateTime,EndDateTime))
    from CallRecords
where TelNum like '0%' )

15. 综合例子2:

create table T_Departments (
department_id int identity(1,1) primary key,
department_name nvarchar(50) )
create table T_Employees (
employee_id int identity(1,1) primary key, employee_name nvarchar(50),
employee_job nvarchar(50),
manager nvarchar(50),
salary int,
department_id int )
insert into T_Departments values('行政部') insert into T_Departments values('财务部') insert into T_Departments values('人资部') insert into T_Departments values('技术部')
insert into T_Employees values('jason','PE','Peter',3000,4) insert into T_Employees values('nina','clerk','Walter',4000,3) insert into T_Employees values('quiet','clerk','walter',3500,3) insert into T_Employees values('ada','clerk','walter',2800,3) insert into T_Employees values('brenda','clerk','walter',4200,3) insert into T_Employees values('wallen','ME','jarry',5000,2) insert into T_Employees values('daniel','MQ','Johnson',3100,1) insert into T_Employees values('crystal','ME','jarry',5600,2) insert into T_Employees values('linda','MQ','Johnson',4100,1) insert into T_Employees values('lily','MQ','Johnson',6200,2) insert into T_Employees values('sunny','clerk','jarry',4700,2) insert into T_Employees values('ken','clerk','Johnson',2600,1)
insert into T_Employees values('wander','clerk','jarry',3100,2) insert into T_Employees values('bill','clerk','Johnson',5300,1) insert into T_Employees values('judy','clerk','Johnson',6800,2) insert into T_Employees values('billy','clerk','Peter',8000,4) insert into T_Employees values('alla','clerk','Peter',2000,4) insert into T_Employees values('Peter','Header',null,9200,4) insert into T_Employees values('Walter','Header',null,13800,3) insert into T_Employees values('jarry','Header',null,8200,2) insert into T_Employees values('Johnson','Header',null,7800,1)

1、列出employees表中各部门的部门号,最高工资,最低工资

select department_Id,max(salary) as 最高工资,min(salary) as 最低工资 from T_Employees group by department_Id

2、列出employees表中各部门employee_job为'clerk'的员工的最低工资,最高工资

select department_Id,max(salary) as 最高工资,min(salary) as 最低工资 from T_Employees where employee_Job='clerk'
group by department_Id

3、对于employees中最低工资小于1000的部门,列出employee_job为'clerk'的员工的部门号,最低工资,最高工资

select department_Id,max(salary) as 最高工资,min(salary) as 最低工资 from T_Employees where department_Id in (select department_Id from T_Employees group by department_Id
having min(salary) < 3000) and employee_Job='clerk' group by department_Id

4、根据部门号由高而低,工资有低而高列出每个员工的姓名,部门号,工资

select employee_Name as 姓名,department_Id as 部门号,salary as 工资 from T_Employees order by department_Id desc,salary asc

5、列出'张三'所在部门中每个员工的姓名与部门号

select employee_Name as 姓名,department_Id as 部门号 from T_Employees where department_Id=(select department_Id from T_Employees where employee_Name='lily')
6、列出每个员工的姓名,工作,部门号,部门名

select e.employee_Name as 姓名,e.employee_Job as 工作,e.department_Id as 部门号, d.department_Name as 部门名
from T_Employees as e join T_Departments as d on e.department_Id=d.department_Id

7、列出employees中工作为'clerk'的员工的姓名,工作,部门号,部门名

select e.employee_Name as 姓名,e.employee_Job as 工作,e.department_Id as 部门号, d.department_Name as 部门名
from T_Employees as e join T_Departments as d on e.department_Id=d.department_Id where e.employee_Job='clerk'

8、对于employees中有管理者的员工,列出姓名,管理者姓名(管理者外键为manager)

select employee_Name as 姓名,manager as 管理者姓名 from T_Employees where manager is not null

9、对于departments表中,列出所有部门名,部门号,同时列出各部门工作为'clerk'的员工名与工作

select d.department_Name as 部门名,d.department_Id as 部门号,e.employee_Name as 员工名, e.employee_Job as 工作
from T_Employees as e join T_Departments as d on e.department_Id = d.department_Id where e.employee_Job='clerk'

10、对于工资高于本部门平均水平的员工,列出部门号,姓名,工资,按部门号排序

select department_Id as 部门号, employee_Name as 姓名,salary as 工资
from T_Employees as a
where a.salary>(select avg(salary) from T_Employees as b where a.department_Id = b.department_Id)
order by department_Id

11、对于employees中工资高于本部门平均水平,人数多与1人的,列出部门号,人数,按部门号排序

select department_Id as 部门号,count(*) as 人数
from T_Employees as a
where a.salary >(select avg(salary) from T_Employees as b where
a.department_Id=b.department_Id) group by department_Id
having count(*)>1
order by department_Id

12、对于employees中低于自己工资至少5人的员工,列出其部门号,姓名,工资,以及工资少于自己的人数 

select department_Id as 部门号, employee_Name as 姓名,salary as 工资,
(select count(b.employee_Id) from T_Employees as b where a.salary>b.salary) as 人数 from T_Employees as a
where (select count(b.employee_Id) from T_Employees as b where a.salary>b.salary)>=5

16.约束: 主键约束、唯一约束、检查约束、默认约束、外键约束

手动添加约束:

唯一约束:右击表-->设计-->索引/键-->然后对对应的内容进行设置即可(命名方式:UQ_表名_字段名)唯一约束的目的:即字段中当已经存在了某项内容,当继续添加时,则不允许。

检查约束:右击表-->设计-->check约束-->在表达式中填写相关约束条件(命名方式:CK_表名_字段名)检查约束的目的:使指定字段满足一定的条件,当不满足的话,则不允许输入。

外键约束:右击外键表-->设计-->关系-->设置对应的主键表及外键字段(命名方式:FK_外键表_主键表_外键字段)
注:含有外键字段的那张表就是外键表,另一张就是主键表外键约束的目的:建立外键表与主键表的一种约束关系。当插入数据的时候,必须先在主键表中进行插入,然后外键表根据主键表的id才能进行相应的插入工作;当进行表删除的时候(如果外键表没有对主键表的记录进行引用,可以直接删除主键表中的那项记录),但外键表对主键表中的记录有引用时,必须先删除外键表对应的记录(即删除了外键表对主键表的引用),再删除主键表相关的记录。

代码实现约束:

Situation One:表已经创建好
唯一约束:alter table 表名 add constraint UQ_表名_字段名 unique(字段名)

检查约束: alter table 表名 add constraint CK_表名_字段名 check(字段名)

默认约束: alter table 表名 add constraint DF_表名_字段名 default(默认值) for 字段名

外键约束:alter table 外键表 add constraint FK_外键表_主键表_外键表中的外键名 foreignkey(外键表中的外键名) references 主键表(主键表中的id)

删除表中的约束:alter table 表名 drop constraint 约束形式_表名_字段名

Situation Two: 在创建表的时候,一起添加约束,Example 

create table TT
(
studentId int identity(1,1) primary key, [name] nvarchar(10) unique not null,
age int check(age>=18 and age<=40) default(20)
)

约束的例子:
--Teacher表中
--tId 主键
--tSex 控制只能是男 女,默认男
--tAge 在30-40之间 默认30

方法一:先建表,再给约束 

create table T_Teacher (
tId int identity(1,1), tSex nvarchar(10), tAge int
)
alter table T_Teacher
add
constraint PK_T_Teacher_tId primary key(tId),
constraint CK_T_Teacher_tSex constraint DF_T_Teacher_tSex constraint CK_T_Teacher_tAge constraint DF_T_Teacher_tAge

方法二:建表的同时添加约束 

create table T_Teacher
(
tId int primary key,
tSex nvarchar(10) check(tSex='男' or tSex='女') default('男'), tAge int check(tAge>=30 and tAge<=40) default(30)
)

17. 视图

视图是一张虚拟表,它表示一张表的部分数据或多张表的综合数据,其结构和数据是建立在对表的查询基础上视图在操作上和数据表没有什么区别,但两者的差异本质是不同的:数据表是实际存储记录的地方,然而视图并不保存任何记录,它存储的实际上是查询语句相同的数据表,根据不同用户的不同需求,可以创建不同的视图(不同的查询语句)视图的目的是方便查询,所以一般情况下不能对视图进行增删改

创建视图:
create view vw_视图名as
SQL语句

执行视图:
select * from vw_视图 


18.局部变量与全局变量 

局部变量(最好使用set给变量赋值):声明: declare @变量名 数据类型赋值: set @变量名 = 值

select @变量名=值(一般为单值) from ...打印结果: print @变量名

-----------------------------------
全局变量(系统变量):
必须以标记@@作为前缀
Example: @@error 表示所有执行的SQL语句,最后一次执行是否出现了错误如果最后一次执行的语句没有错误,则@@error值为0 


19.if else 语句

if 条件

begin

end

else

begin

end

Example1[查找是否存在叫梦琪的人,有就打印出此人信息,没有则打印'查无此人']: 

if (select count(*) from MyStudent where FName='梦琪')>0
begin
select * from MyStudent where FName='梦琪'
end else
begin
print '查无此人'
end

Example2[计算english平均分,如果平均分超过60,输出成绩最高的三个学生的成绩,否则输出后三名的学生] 

declare @avgScore float
set @avgScore=(select avg(english) as 平均分 from score) print '平均分是:'+convert(varchar(50),@avgScore) if(@avgScore>=60)
begin
select top 3 * from score order by english desc
end else
begin
select top 3 * from score order by english asc
end

20. while语句 

Example1:计算1+2+...+100的值 

declare @index int
declare @sum int
set @index=1
set @sum=0 while(@index<=100) begin
       set @sum=@sum+@index
set @index=@index+1 end
print @sum

Example2:如果不及格的人超过半数(考试题出难了),则给每个人增加2分,循环加,直到不及格的人数少于一半。 

declare @losers int
set @losers=(select count(*) from score where english<60) declare @halfCount int
set @halfCount=(select ceiling(count(*)/2.0) from score) while(@losers<@halfCount)
begin
update score set english=english+2 where english<60
set @losers=(select count(*) from score where english<60) end


21.事物[Transaction](就是由多个sql语句组成,必须作为一个整体执行!要么都执行,要么都不执行): 

事物语法步骤:
开始事物:begin transaction

事物提交:commit [transaction]

事物回滚:rollback [transaction]

【银行转账问题】--没有用事务范例(建表并添加约束,编号0001向0002转账,自己钱没有少,但0002的钱多了!) 

create table bank
(
cId char(4) primary key,
balance money, --余额
)
alter table bank
add constraint CH_balance check(balance >=10)
go
--delete from bank
insert into bank values('0001',1000) insert into bank values('0002',10) go
update bank set balance=balance-1000 where cid='0001' update bank set balance=balance + 1000 where cid='0002'

执行update语句之后,编号为0001的金额不会少,因为它受check约束,只有当余额至少为为1100的时候,才能进行转账业务,所以他转不了,但0002的不会受限制,所以还是增加了1000!

使用事务解决上面的问题:

Method One(可以实现,结果正确,但第一句update语句还是会报错,有check约束): 

begin transaction
declare @myError int
set @myError=0 //要初始化,不然默认值为null
update bank set balance=balance-100 where cid='0001' set @myError=@myError+@@error
update bank set balance=balance + 100 where cid='0002' set @myError=@myError+@@error
if(@myError=0)
begin commit
end else
begin rollback
end

Method Two(用try--catch捕获异常!如果update语句没有问题,则正常执行;否则,打印异常) 

begin transaction
begin try
update bank set balance=balance-100 where cid='0001' update bank set balance=balance + 100 where cid='0002' --没有错误就执行上面的两句代码
commit
end try begin catch
print '有错误' --回滚条件,update语句一句都不执行 rollback
end catch

22. 存储过程(就像数据库中运行方法) 

存储过程与函数的区别:

1.一般来说,存储过程实现的功能要复杂一点,而函数的实现的功能针对性比较强。

2.对于存储过程来说可以返回参数(output),而函数只能返回值或者表对象。

3.存储过程一般是作为一个独立的部分来执行,而函数可以作为查询语句的一个部分来调用,由于函数可以返回一个表对象,因此它可以在查询语句中位于FROM关键字的后面。

优点:
执行速度更快 – 在数据库中保存的存储过程语句都是编译过的允许模块化程序设计 – 类似方法的复用
提高系统安全性 – 防止SQL注入
减少网络流通量 – 只要传输 存储过程的名称

系统存储过程一般以sp开头,用户自定义的存储过程一般以usp开头

定义存储过程语法create proc 存储过程名

  1. @参数1  数据类型 [=默认值] [output],

  2. @参数2  数据类型 [=默认值] [output],

...

as
SQL语句

执行存储过程语法:exec 存储过程名

Example One:
定义存储过程:

create proc usp_StudentByGenderAge
@gender nvarchar(10) [='男'],
@age int [=30]
as
select * from MyStudent where FGender=@gender and FAge=@age

执行存储过程:
Situation One(调用默认的参数):

exec usp_StudentByGenderAgeSituation Two(调用自己指定的参数):

exec usp_StudentByGenderAge '女',50
或者指定变量名 exec usp_StudentByGenderAge @age=50,@gender='女' 

alter proc usp_StudentByGenderAge
@gender nvarchar(10) [='男'],
@age int [=30], --加output表示该参数是需要在存储过程中赋值并返回的 @recorderCount int output
as
select * from MyStudent where FGender=@gender and FAge=@age
set @recorderCount=(select count(*) from MyStudent where FGender=@gender and FAge=@age)说明:将上面的存储过程修改一下,加一个返回记录的条数

说明:将上面的存储过程修改一下,加一个返回记录的条数

--output参数的目的,就是调用者需要传递一个变量进来,然后在存储过程中为该变量完成赋值工作,存储过程执行完成以后,将执行的对应结果返回给传递进来的变量。(与C#中的out原理一模一样)

调用(记住这里的语法!)因为该存储过程前面还有其他参数,所以要把 @recorderCount写上,该存储过程执行后,相当与完成了以上的查询工作,同时将查询结果得到的条数赋值给了@count变量。(@count是当做参数传给usp_StudentByGenderAge,当存储过程执行完毕以后,将得到的条数返回给@count) 

declare @count int
exec usp_StudentByGenderAge @recorderCount=@count output print @count

Example Two: 银行转账问题(存储过程版本) 

create proc usp_tranMoney @exportId nvarchar(max), @importId nvarchar(max), @money money
as
begin
begin tran
declare @exportLeftMoney money
set @exportLeftMoney=(select salary from T_tran where id=@exportId) if @exportLeftMoney-@money>=10
begin
update T_tran set salary=salary-@money where id=@exportId update T_tran set salary=salary+@money where id=@importId commit
end else
begin rollback
end end

Example Three:分页(存储过程版)

create proc usp_page
@page int, ---一页显示多少条记录 @number int, ---用户选择了第几页数据 as
begin
select * from
--小括号里面内容是专门得到排列好的序号 (
select *, ROW_NUMBER() over(order by(Fid)) as number
from MyStudent ) as t
where t.number>= (@number-1)*@page+1 and t.number<=@number*@page end

23.触发器其是一种特殊的存储过程。

一般的存储过程是通过存储过程名直接调用,而触发器主要是通过事件(增、删、改)进行触发而被执行的。其在表中数据发生变化时自动强制执行。常见的触发器有两种:after(for)、instead of,用于insert、update、delete事件。

after(for) 表示执行代码后,执行触发器

instead of 表示执行代码前,用已经写好的触发器代替你的操作

触发器语法:

create trigger 触发器的名字for|after instead ofupdate|insert|delete
as

SQL语句

on 操作表

Example1 

--禁止用户插入数据(实际上是先插入,然后立刻将其删除!)
create trigger tr_insert on bank
for --for表示执行之后的操作
insert --即先执行了插入操作,同时在临时表中保存了插入记录 as
--执行完插入之后,在新生成的表中将刚刚插入的那条记录删除,
--而此时得到的刚刚插入的记录的id是通过临时表 inserted得到的 delete * from bank where cid=(select cid from inserted)

生成上面的触发器后,当用户再输入insert语句后就见不到效果了!如:insert into bank values('0004',10000),是插入不进数据库的。 

Example2:有两张表,学生表和成绩表,当向学生表中插入数据,如果学生的课程Id在课程表中不存在,则执行after触发器,禁止插入

create table T_Student
(
Stuid int identity(1,1) primary key, StuName nvarchar(50),
CourseId int
)
create table Course (
CourseId int ,
   CouName nvarchar(50)
)
insert into Course values(1,'语文') insert into Course values(2,'数学') insert into Course values(3,'英语')

触发器如下:

create trigger tri_Student_insert on T_Student
after insert
as
begin
//判断刚插入的数据在课程表中是否有对应的课程id
if not exists(select * from Course where CourseId=(select CourseId from inserted)) begin
delete from T_Student where CourseId=(select CourseId from inserted)
end
end

Example3:

--删除谁就让谁的账户加上10元
create trigger tr_dalete on bank
instead of
delete
as
update bank balance=balance+10 where cid=(select cid from deleted) 

生成这个触发器之后,当用户输入delete语句后,对应的那个id不但没有被删除掉,而且他的账户增加了10元 , 如:

delete from bank where cid='0002',执行完这句话后,编号为0002的账户会增加10元

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章