数据库原理及应用与实践 SQL Sever 笔记

白色框框里面的是语法格式(其中用[]括起来的表示可写可不写的内容),黑色代码框框里面的是例题的解答

介绍

数据库系统的发展、概念及特点:略
数据库系统的数据模型:略
数据库和应用程序的关系👇请添加图片描述请添加图片描述
请添加图片描述

SQL语句分类

DQL(数据查询语言): 查询语句,凡是select语句都是DQL。
DML(数据操作语言):insert delete update,对表当中的数据进行增删改。
DDL(数据定义语言):create drop alter,对表结构的增删改。
TCL(事务控制语言):commit提交事务,rollback回滚事务。(TCL中的T是Transaction)
DCL(数据控制语言): grant授权、revoke撤销权限等。

函数查看

请添加图片描述

数据类型

1.数值型
(1)整数数据 bit, tinyint, smallint, int, bigint
(2)带固定精度和小数位数的精确数值 decimal, numeric
(3)近似数值 float, real
2.字符/字符串
(1)char(n) / nchar(n)
(2)varchar(n) / nvarchar(n)
(3)text(n) / ntext(n)
3.日期和时间
(1)datetime
(2)smalldatetime
(3)date
(4)time(n)
(5)datetime2(n)
(6)datetimeoffset(n)

表达式优先级

请添加图片描述

数据库

创建一个数据库

create database 图书销售
on	/*创建主文件*/
(
	name = 图书销售,//此句不可省略
	filename = 'D:\my_database\图书销售.mdf',//此句不可省略
	size = 10mb,
	maxsize = unlimited,	/*主文件最大文件大小无限制*/
	filegrowth = 1mb	/*主文件增量为1mb*/
)
log on	/*创建日志文件*/
(
	name = 图书销售_log,
	filename = 'd:\my_database\图书销售_log.ldf',
	size = 5mb,
	maxsize = 15mb,		/*日志文件最大文件大小为15mb*/
	filegrowth = 10%	/*日志文件增量为10%*/
)

修改数据库名

alter database 原数据库名 modify name = 新数据库名
//或者
sp_renamedb 原数据库名,新数据库名

修改数据库

alter database 数据库名
add或modify file或log file --分别为增加、修改(日志或主或辅助)文件
alter database <数据库名>
	  modify file
	  ( name = ‘逻辑名’,
               size = 修改后的大小,
               maxsize = 修改后的最大容量(大小),
	    filegrowth = 新的增长方式)

删除数据库

drop database 数据库名

数据表的创建

建立数据表

注意:一个表的外键关联到主表的主键约束或者unique约束都可以,不一定非要主键约束

create database 图书销售--先建数据库
on
(
	name  = 图书销售,
	filename = 'd:\my_database\图书销售.mdf'
)

log on
(
	name = 图书销售_log,
	filename = 'd:\my_database\图书销售_lof.ldf'
)

sp_helpdb 图书销售--查看数据库信息
sp_help 图书--查看数据表信息
sp_help 售书网站

create table 图书
(
	图书编号 char(10) primary key,--图书编号设置为主键
	图书名 nvarchar(30) not null unique,--列完整性约束:not null,唯一性约束:unique
	出版社 nvarchar(30),
	作者 nvarchar(10),
	价格 real default 0 ,--默认约束:默认值给0,如果是中文要加''
	出版时间 date
)

create table 售书网站
(
	售书网站编号 char(10) not null,
	名称 nvarchar(30) not null,
	所在城市 nvarchar(10) not null,
	成立时间 date,
	primary key(售书网站编号),--表级完整性约束
	unique(名称),--表级完整性约束
	
)

alter table 售书网站
add default '北京' for 所在城市 --修改表 → 售书网站 中的列 → 所在城市

create table 售书--要先对有主键的表录入信息后才可以对有外键的表录入信息
(
	图书编号 char(10) foreign key references 图书(图书编号),--外键:引用自图书表的图书编号
	售书网站编号 char(10),
	数量 int check(数量>=0 and 数量<=100),
	primary key(图书编号,售书网站编号),--多字段主键,又称联合主键
	foreign key(售书网站编号) references 售书网站(售书网站编号)--外键:引用自售书网站的售书网站编号
)
use bookDB--bookDB是已经创建了的数据库
create table 出版社
(
	出版社ID int primary key identity(1,1),--identity(seed,increment) 自动编号的标识列,seed为起始值,increment为增量值
	出版社名称 varchar(50) not null unique,
	出版社简称 varchar(16) unique,
	出版社地址 varchar(50),
	邮政编码 char(6)
)

create table 图书信息
(
	ISBN编号 varchar(20) primary key,
	图书名称 varchar(100) not null,
	作者 varchar(40),
	价格 money not null,
	出版社 int not null foreign key references 出版社(出版社ID),--外键和引用的主键的名称不需要完全相同
	出版日期 date check(出版日期<=getdate()),
	图书类型 varchar(2) not null foreign key references 图书类型(图书类型代号),
	封面图片 varchar(100),
	图书简介 varchar(500)
)

数据表操作

数据表结构的修改和删除

ALTER TABLE <基本表名>
[ADD <新列名> <列数据类型> [列完整性约束]]
[DROP COLUMN <列名>]
[ALTER COLUMN <列名> <列数据类型> [列完整性约束]]
--在售书网站的数据表中增加一个地址列
alter table 售书网站 add 地址 nvarchar(100) 
--在图书数据表中删除出版时间列
alter table 图书 drop column 出版时间 
--修改售书网站的数据表中的“地址”列的数据类型为NVARCHAR(50)
alter table 售书网站 alter column 地址 NVARCHAR(50)
--原先的列如果是not null,修改数据类型后会变成null,所以要在命令后面加上 not null
alter table 售书网站 alter column 所在城市 NVARCHAR(20)

alter table 图书借阅 alter column 图书状态 char(1)执行结果👇
由于一个或多个对象访问此 列,ALTER TABLE ALTER COLUMN 图书状态 失败。
原因:要修改的键含有约束,需要先删除此键的约束才能修改图书状态(键名用sp_help命令查询)👇
请添加图片描述

删除约束

alter table 表名 drop constraint 约束名或键

增加约束

1、主键约束  PK_
alter table 表名 add constraint 约束名称 primary key(列名)
2check约束  CK_
alter table 表名 add constraint 约束名称 check(条件)
3unique约束  UQ_
alter table 表名 add constraint 约束名称 unique(列名)
4、默认约束  DF_
alter table 表名 add constraint 约束名称 default(默认值) for 列名
5、外键约束  FK_
alter table 表名 add constraint 约束名称 foreign key(列名) references 被引用的表名(列名)

数据查询

SELECT [ALL|DISTINCT] 表列名或列表达式[,表列名或列表达式] …
FROM 表名或视图名[,表名或视图名]…
[WHERE <行条件表达式>]
[GROUP BY列名
[HAVING <组条件表达式>]]
[ORDER BY列名[ASC|DESC],...]

请添加图片描述
distinct 只能出现在所有字段的最前面
表名.* 表示该表中所有列名

select  出版社名称,出版社简称,出版社地址 from 出版社
select * from 出版社
select * from 图书信息

select ISBN编号 ISBN, 图书名称 bookName, 出版社 publishingHouse from 图书信息--查询时更改列标题

select ISBN编号,总藏书量,馆内剩余,总藏书量-馆内剩余 借出数量 from 藏书信息--查询时使用计算列:得到的借出数量列为:总藏书量-馆内剩余

select top 3 出版社名称,出版社简称,出版社地址 from 出版社--top关键字:检索前3个出版社的:出版社名称、简介、地址,数字替换为百分数  10 percent  检索前10%的

select top 10 * from 藏书信息 order by 总藏书量--从藏书信息表中查询总藏书量最少的10条藏书记录


select distinct 图书类型 from 图书信息--distinct关键字:distinct后的键在索引时重复的键值会自动去除

select *from 图书信息 where 价格>=20 and 价格<=30 --检索价格在[20,30]的图书的信息,也可以是between 20 and 30 在前面加not表示否定

select *from 出版社 where 邮政编码 in ('100011','100012')--检索属于集合内的值的键的出版社信息,在前面加not表示否定

select *from 图书信息 where 图书简介 is not null--检索图书简介不为null的图书信息

--从“图书信息”数据表中检索作者为“陈承欢”,出版日期在“2009”年之后的图书信息
select *from 图书信息 where 作者 = '陈承欢' and 出版日期 <='2016-12-31'
--从“图书信息”数据表中检索出版日期在“2008-1-1”和“2010-1-1”之间的图书信息
select *from 图书信息 where 出版日期 between '2008-1-1' and '2010-1-1'
--从“图书信息”数据表中检索出“陈承欢”,“陈启安”,“陈海林”三位作者编写的图书信息
select *from 图书信息 where 作者 = '陈承欢'or 作者 = '陈启安' or 作者 ='陈海林'

模糊查询

<列名> [NOT] LIKE <字符串常数>[ESCAPE <转义字符>]

	  其中,<字符串常数>可以使用两个通配符:
      1、% (百分号)。代表任意长度(可以为0)的字符串。如a%b表示以a开头,以b结尾的任意长度的字符串。如acb,addgb,ab等都满足该匹配串。
      2、 _ (下划线)。代表任意一位单字符。如a_b表示以a开头,以b结尾的长度为3的任意字符串。如acb,afb等都满足该匹配串。
      3、 [] 。表示筛选范围。如张[a-z],则张a,张b……,张z等都满足该匹配串。
      4、^ 。表示非。如张[^0-9],则张三,张a,等都满足该匹配串,但张8不满足
--从“图书信息”数据表中检索出作者姓“陈”的图书信息
select * from 图书信息 where 作者 like '陈__'

--从“图书信息”数据表中检索出作者姓名只有3个汉字并且不是姓“陈”的图书信息
select * from 图书信息 where 作者 not like '陈%' and Len(作者)=3
--或者
select * from 图书信息 where 作者 like '[^陈]__'
--或者
select * from 图书信息 where 作者 not like '陈%' and 作者 like '___'

聚合函数查询

请添加图片描述

--count(列名)表示统计非空字段的数量,count(distince 列名)表示统计非空不重复字段的数量,count(*)统计记录的条数

---从 图书信息 中查询价格在20~45的图书种数
select count(*) as 图书种数 from 图书信息 where 价格 between 20 and 45
--从 藏书信息 中查询图书的藏书总数量
select sum(总藏书量) as 藏书总数量 from 藏书信息
--从藏书信息中查询无重复的藏书位置的总数
select count(distinct 藏书位置) as 无重复的藏书位置的数量 from 藏书信息
--从“图书信息”中查询图书的最高阶、最低价和平均价格
select max(价格) as 最高价,min(价格) as 最低价,avg(价格) as 平均价格 from 图书信息

--从“图书信息”数据表中查询 “网络”相关书籍的图书种数。
select count(*) as 网络相关图书种数 from 图书信息 where 图书名称 like '%网络%'
--从“图书借阅”数据表中查询借阅了图书的人数
select count(distinct 借书证编号) as 借阅了图书的人数 from 图书借阅
--从“藏书信息”数据表中查询图书的藏书总数量,馆内总剩余及总借出量
select sum(总藏书量) as 图书的藏书总数量,sum(馆内剩余) as 馆内总剩余,(sum(总藏书量)-sum(馆内剩余)) as 总借出量 from 藏书信息 
--从“读者类型”数据表中查询最大限借数、最小限借数和平均限借数
select max(限借数量) as 最大限借数 ,min(限借数量) as 最小限借数量,avg(限借数量) as 平均限借数 from 读者类型
select 借书证编号,图书编号,借出日期,datediff(d,借出日期,getdate()) as 借出天数 from--在图书借阅表中查询借书证编号,图书编号,借出日期和借出天数,其中借出天数为计算字段,即当前时间与借出日期之差(提示:利用datediff()函数)

排序查询

SELECT [ALL|DISTINCT]表列名或列表达式[,表列名或列表达式] …
FROM 表名或视图名[,表名或视图名]…
[WHERE <行条件表达式>]
[GROUP BY列名
[HAVING <组条件表达式>]]
[ORDER BY列名[ASC|DESC],...]

ASC是升序,DESC是降序,[ORDER BY列名[ASC|DESC]只能放在最后一句的位置,不写asc或不写desc则默认为asc

--从“图书信息”数据表中检索价格在30元以上的图书信息,要求按价格的升序输出
select *from 图书信息 where 价格>=30 order by 价格
--从“图书信息”数据表中检索2006年以后出版的图书信息,要求按作者姓名的降序输出
select *from 图书信息 where year(出版日期) >2006 order by 作者 desc
--从“图书信息”数据表中检索所有的图书信息,要求按出版日期的升序输出,出版日期相同的按价格的降序输出
select *from 图书信息  order by 出版日期 , 价格 desc

数据分组与汇总

HAVING是汇总,有分组(GROUP BY 列名)不一定有汇总,但是有汇总则一定有分组

SELECT [ALL|DISTINCT]表列名或列表达式[,表列名或列表达式] …
FROM 表名或视图名[,表名或视图名]…
[WHERE <行条件表达式>]
[GROUP BY列名
[HAVING <组条件表达式>]]
[ORDER BY列名[ASC|DESC],...]
--在“图书信息”数据表中查询图书平均定价在20元并且图书种数在6种以上的出版社,查询结果按平均定价降序排列
--group by 就是依据by 后面的列名对select的数据进行分组,在结果框输出结果
select 出版社,avg(价格) as 平均定价,count(图书类型) as 图书种数 from 图书信息 group by 出版社 
having avg(价格)>20 and count(图书类型)>6
order by avg(价格) desc

--将上一步的查询结果保存到数据表“出版社0401”中
Select 出版社,AVG(价格) As 平均定价,COUNT(*) As 图书种数 
Into 出版社0401
From 图书信息
Group By 出版社
Having AVG(价格)>20 And COUNT(*)>6
Order By 平均定价 DESC
--在“图书借阅”数据表中查询借阅了两本及两本以上图书的借书证编号,及相应的借书数,查询结果按借书数降序,借书证升序排列。并将查询结果保存到数据表“借书”中
select 借书证编号,count(图书编号) as 借书数量 
into 借书
from 图书借阅
group by 借书证编号
having count(图书编号)>=2
order by 借书数量 desc,借书证编号

注意
结果框中显示的信息仅仅只是代码运行的结果,要想把分组与汇总的结果保存下来,就要使用into语句
运行结果中有“XX行受影响”一般不是执行失败,刷新表,发现数据保存成功说明执行成功

多表连接

请添加图片描述

前面两张表连接的筛选结果与下一张连接的表进行连接筛选以此类推向后连接得到最终结果(而不是一对多)
在左外连接和右外连接时都会以一张表为基表,该表的内容会全部显示,然后加上两张表匹配的内容。相匹配的条件写在on后面,如果基表的数据在另一张表没有记录。那么在相关联的结果集行中列显示为空值(NULL)
左外连接=左表全部记录+相关联结果
右外连接=右表全部记录+相关联结果
全外连接:左表和右表都不做限制,所有的记录都显示,两表不足的地方用null 填充

/*从“图书类型”和“图书信息”两个数据表中查询所有图书类型的图书信息,
查询结果显示图书类型名称、图书名称和价格3列数据。(左外连接,右外连接) */
select 图书名称,价格,图书类型名称
from 图书类型 left join 图书信息 on
图书信息.图书类型 = 图书类型.图书类型代号
select 图书名称,价格,图书类型名称 
from 图书信息 right join 图书类型 on
图书信息.图书类型 = 图书类型.图书类型代号
/*从“图书借阅”和“借书证”两个数据表中查询所有借书证的借书情况,
查询结果显示借书证编号、姓名、图书编号和借出数量4列数据。 */
/*左外*/
select 借书证.借书证编号,姓名,图书编号,图书借阅.借出数量
from 借书证 left join 图书借阅 on 借书证.借书证编号 = 图书借阅.借书证编号
/*右外*/
select 借书证.借书证编号,姓名,图书编号,图书借阅.借出数量
from 图书借阅 right join 借书证 on 借书证.借书证编号 = 图书借阅.借书证编号

/*从“借书证”、“图书借阅”“藏书信息”和“图书信息”4个数据表中查询
所有借书证借阅图书的情况和所有图书被借阅的情况,查询结果包括借书证编号
、借出日期、图书名称和总藏书量4列数据。*/
--需要查询的表:图书借阅,图书信息,藏书信息,借书证
/*全外连接*/
select 借书证.借书证编号,借出日期,图书名称,总藏书量
from 借书证 full join 图书借阅 on 借书证.借书证编号 = 图书借阅.借书证编号
join 藏书信息 on 图书借阅.图书编号 = 藏书信息.图书编号
join 图书信息 on 图书信息.ISBN编号 = 藏书信息.ISBN编号

联合连接

查询结果的结构完全一致时的两个查询,可以进行并(UNION)、交(INTERSECT)、差(EXCPT)操作。
union是合并且排除重复的结果,union all是合并且不排除重复的结果

/**图书管理数据库中的数据表“借阅者信息”中的数据主要包括教师和学生两大类
,而在教务管理数据库中已有“教师”数据表和“学生”数据表,其中“教师”数据表
包括4个字段,分别为职工编号、姓名、性别和部门名称,“学生”数据表也包括4个字段,
分别为学号、姓名、性别和班级名称。使用联合查询将两个数据表的数据合并(教师数据
在前,学生数据在后),并存入1个新表“借阅者0401”中,联合查询时增加1个新列
“借阅者类型”,其值分别为“教师”和“学生”。然后修改新表“借阅者0401”的
字段名称,“职工编号”修改为“借阅者编号”。 */
select 职工编号 as 借阅者编号,姓名,性别,部门名称, '教师' as 借阅者类型
into 借阅者0401
from 教师
union all
select *, '学生' as 借阅者类型 from 学生

嵌套查询

经常和联合查询发挥同一作用
注意:嵌套的语句查询得到的结果有单值多值两种情况,需要用不同的运算符来实现嵌套;所以要从数据最后一个嵌套语句开始一边得到嵌套语句得到的是单值还是多值一边判断使用哪种运算符来实现嵌套

--两种方法查找图书《C#程序设计案例教程》是由哪一家出版社出版的(关键词:出版社,出版社名称)
--连接查询
select 出版社名称 
from 出版社 left join 图书信息 on 出版社.出版社ID=图书信息.出版社
where 图书名称='C#程序设计案例教程'
--嵌套查询
select 出版社名称 from 出版社 where 出版社ID=(
select 出版社 from 图书信息 where 图书名称 = 'C#程序设计案例教程')

--价格大于清华大学出版社出版的所有/任意图书价格的图书信息。(关键词:出版社,价格,图书信息)
select *from 图书信息 where 价格>all(
select 价格 from 图书信息 where 出版社=(
select 出版社id from 出版社 where 出版社名称 = '清华大学出版社'))

select *from 图书信息 where 价格>any(
select 价格 from 图书信息 where 出版社=(
select 出版社id from 出版社 where 出版社名称 = '清华大学出版社'))

--查询借阅了图书编号为'TP7040273144'的借阅人的编号和姓名
select 借书证编号,姓名 from 借书证 where 借书证编号=(
select 借书证编号 from 图书借阅 where 图书编号='TP7040273144')

--查询‘丁一’借阅的图书的ISBN编号和图书名称
--都是单值嵌套
select ISBN编号,图书名称 from 图书信息 where ISBN编号=(
select ISBN编号 from 藏书信息 where 图书编号=(
select 图书编号 from 图书借阅 where 借书证编号 = (
select 借书证编号 from 借书证 where 姓名 = '丁一')))

--查询超期日罚金比‘教师’和‘学生’都高的读者类型
select 读者类型名称 from 读者类型 where 超期日罚金>(
select max(超期日罚金) from 读者类型 where 读者类型名称='教师')
and 超期日罚金>(select max(超期日罚金) from 读者类型 where 读者类型名称='学生')
--或者
select 读者类型名称 from 读者类型 where 超期日罚金>all(
select 超期日罚金 from 读者类型 where 读者类型名称='教师' or 读者类型名称='学生')
--或者
select 读者类型名称 from 读者类型 where 超期日罚金>(
select max(超期日罚金) from 读者类型 where 读者类型名称='教师' or 读者类型名称='学生')
--或者
select t2.读者类型名称 from 读者类型 as t1 join 读者类型 as t2 on t1.超期日罚金 >t2.超期日罚金
where t2.读者类型名称 = '教师' --join左右两张表的表名和列名都同名时,要分别对表其起别名,才能区分比较的列

--查询‘金鑫’借阅的图书的ISBN编号和图书名称
--涉及单值和多值嵌套
select ISBN编号,图书名称 from 图书信息 where ISBN编号 in(
select ISBN编号 from 藏书信息 where 图书编号 in(
select 图书编号 from 图书借阅 where 借书证编号 = (
select 借书证编号 from 借书证 where 姓名 = '金鑫')))

--查询由“高等教育出版社”出版已被借出的图书信息
--嵌套查询(多值)
select * from 图书借阅 where 图书编号 in(
select 图书编号 from 藏书信息 where ISBN编号 in (
select ISBN编号 from 图书信息 where 出版社=(
select 出版社ID from 出版社 where 出版社名称 = '高等教育出版社')))
--自连接查询
select * from 图书信息 join 出版社 on 图书信息.出版社 = 出版社.出版社ID
join 藏书信息 on 图书信息.ISBN编号 = 藏书信息.ISBN编号
join 图书借阅 on 图书借阅.图书编号 = 藏书信息.图书编号
where 出版社名称 = '高等教育出版社'

相关子查询

--查询所有借阅了图书的借书证编号、借书人姓名,读者类型
--嵌套查询(多值)
select 借书证编号,姓名,读者类型 from 借书证 where 借书证编号 in(
select 借书证编号 from 图书借阅)
--连接查询
select distinct 借书证.借书证编号,姓名,读者类型 from 借书证 
join 图书借阅 on 借书证.借书证编号=图书借阅.借书证编号
/*相关子查询:把主表中的指定列的信息全部按行依次在子查询中判断是否符合子查询的where条件
,符合条件的行被筛选出来成为查询结果,子查询中select后面跟的列名没有任何作用,
不存在则用not exists */
select 借书证编号,姓名,读者类型 from 借书证 where exists(
select * from 图书借阅 where 图书借阅.借书证编号=借书证.借书证编号)

数据操作

数据插入

insert into 表名(列名,...)
values(列对应的数据,...)
insert into 学生(学号,姓名,性别,班级名称)
values('343214234','zhangsan','女','计算机2003')
--简写为
insert into 学生
values('343214234','zhangsan','女','计算机2003')
--因为学生表中的列只有4个,且插入的值正好也是4个,所以“学生”后面的内容可以省略不写,如果插入的值的数目不是列总数则表名后面要有值对应的列名
insert into 学生(学号,姓名,性别)
values('3413245','李丽','女')--每个值顺序对应列名

--对“藏书信息”数据表中各个出版社的藏书数量和总金额进行统计,
--并存储到数据表“图书_total”中。
select 出版社名称,sum(总藏书量) as 藏书数量, sum(价格*总藏书量) as 总金额
into 图书_total
from 藏书信息 join 图书信息 on 藏书信息.ISBN编号 = 图书信息.ISBN编号
join 出版社 on 图书信息.出版社 = 出版社.出版社ID
group by 出版社名称
--或者
create table 图书_total(
	出版社名称 varchar(50),
	藏书数量 int,
	总金额 float
)
insert into 图书_total--此命令需要已存在图书_total表才可以执行成功,所以需要先创建表
select 出版社名称,sum(总藏书量) as 藏书数量, sum(价格*总藏书量) as 总金额
from 藏书信息 join 图书信息 on 藏书信息.ISBN编号 = 图书信息.ISBN编号
join 出版社 on 图书信息.出版社 = 出版社.出版社ID
group by 出版社名称

修改数据

UPDATE <基本表名>
SET 列名 = 表达式 ,列名 = 表达式…
WHERE <条件表达式>
--将“图书信息”数据表中ISBN编号为“9787115195919”的图书的“图书简介”修改为“XXXXXX”
update 图书信息 set 图书简介 = 'XXXXXX'
where ISBN编号 = '9787115195919'
--将“读者类型”数据表中除学生之外的读者的“超期日罚金”提高0.5元,“限借数量”减少5本
update 读者类型 set 超期日罚金 = 超期日罚金 + 0.5, 限借数量 = 限借数量 - 5
where 读者类型名称 != '学生'

删除数据

删除指定行👇

DELETE FROM 基本表名 
WHERE <条件表达式>

注意:delete只是删除指定行的数据,drop 表名 是把表包括数据都删除了

/*首先在“图书信息”和“藏书信息”中分别插入1条记录,
ISBN编号为“9787115206060”,图书名称为“SQL Server 2008 基础教程”,
作者为“Robin Dewson”,价格为“55.0”,出版社ID为“2”,出版日期为
“2008年5月1日”,版次为“1”,图书编号为“TP7115206060”,总藏书量为
“20”,馆内剩余为“20”,藏书位置为“A-1-1”。
然后分别删除刚才插入的记录。*/
--因为藏书信息的ISBN编号是外键(来自图书信息表),所以要先把主键表数据(图书信息表)插入才能插入外键表数据(藏书信息表)
insert into 图书信息(ISBN编号,图书名称,作者,价格,出版社,出版日期) 
values ('9787115206060','SQL Server 2008 基础教程','Robin Dewson',55.0,2,'2008-5-1','T')
insert into 藏书信息(图书编号,ISBN编号,总藏书量,馆内剩余,藏书位置,入库时间)
values ('TP7115206060','9787115206060',20,20,'A-1-1',GETDATE())
--或者
insert into 图书信息
values ('9787115206060','SQL Server 2008 基础教程','Robin Dewson',55.0,2,'2008-5-1','T',NULL,NULL)
insert into 藏书信息
values ('TP7115206060','9787115206060',20,20,'A-1-1',GETDATE())
--要先删除外键表,再删除主键表,原因同上
delete from 藏书信息 where ISBN编号='9787115206060'
delete from 图书信息 where ISBN编号='9787115206060'

索引和视图

索引

聚集索引:其顺序和表中数据的物理顺序一致,相当于目录,所以一个表中只能有一个聚集索引
非聚集索引:相当于索引,一个表中可以有多个非聚集索引
在创建主键或唯一性约束时,系统会自动创建主键索引或唯一性索引
创建索引

CREATE [UNIQUE] [CLUSTERED∣NONCLUSTERED] 
INDEX <索引名> ON <表名|视图名> (<列名>[<次序>],[<列名>[<次序>]]…)

说明:UNIQUE表明建立唯一索引。选CLUSTER表示建立聚集索引,选NONCLUSTER为非聚集索引,不写则默认非聚集索引,“次序”用于指定索引值的排列顺序,可为ASC(升序)或DESC(降序),缺省值默认为升序。
查看指定表的索引:sp_helpindex 表名

--在图书管理数据库中,经常要按照“图书名称”查询图书,
--希望创建索引提高查询速度,索引名称为“IX_bookname”
create index IX_bookname on 图书信息(图书名称)

--在图书管理数据库中,“部门”数据表中的“部门编号”要求唯一,
--创建1个唯一聚集索引,索引名称为“IX_部门编号”,“部门名称”
--也要求不重复,创建一个唯一非聚集索引,索引名称为“IX_部门名称”
create unique clustered index IX_部门编号 on 部门(部门编号)
create unique index IX_部门名称 on 部门(部门名称)

drop index IX_部门编号 on 部门 
alter table 部门 add constraint pk_部门编号 primary key(部门编号)

利用SQL中的命令删除索引
DROP INDEX <索引名> ON <表名>
注意:因为不同表中的索引名允许相同,所以删除索引时需要有指定的表名

视图

视图是从基本表或其他视图导出的一种虚表(即显示的内容是数据的映射),为用户提供对数据多种角度的观测,程序可以建立在视图上,简化用户操作,使数据更加安全

视图创建

CREATE VIEW <视图名> [(<列名1>[,<列名2>]…)]
[WITH ENCRYPTION] 
AS 
(子查询)
[WITH CHECK OPTION] 

with encryption 表示对脚本加密,则无法查看视图到的脚本
with check option 表示对插入视图的数据进行检查,检查的规则为创建视图语句中的子查询语句

视图操作

视图的修改:视图的修改比较大动刀斧,相当于新建了新的视图
ALTER VIEW <视图名>
	[WITH ENCRYPTION]
AS 
	(子查询)
	[WITH CHECK OPTION]
	
查询视图: select * from 视图名
查看视图的脚本:sp_helptext 视图名
视图删除:DROP VIEW <视图名>
视图重命名操作:sp_rename old_name, new_name 
通过视图更新表数据:UPDATE  <视图名>
通过视图插入表数据:INSERT INTO  <视图名> Values (对应值列表)
通过视图删除表数据的语句:DELETE FROM  <视图名> WHERE <条件表达式>

存储过程

存储过程(Stored Procedure)是数据库系统中,一组完成特定功能的SQL语句集。经编译后存储在数据库中,用户通过指定存储过程名及给出参数(若此存储过程带有参数)进行调用执行。
SQL Server提供了一种方法,可将一些固定的操作集中由SQL Server数据库服务器完成,以实现某个处理任务,这种方法就是存储过程。
存储过程是一组相关的T-SQL语句集合,提供了一种封装任务的方法,并具有强大的编程功能。
存储过程包括4个方面:
(1)包含在数据库中执行操作的语句,包括调用(执行)其他存储过程。
(2)接受输入具体参数。
(3)返回指示成功或失败的状态值。
(4)以输出参数的形式,将多个值返回到发起调用的存储过程或客户端应用程序。

存储过程的特点
(1)在服务器注册后,可以提高T-SQL语句执行效率.
(2)存储过程具有安全性和所有权链接,可执行所有的权限管理。用户可以被授予执行存储过程的权限,而不必拥有直接对存储过程中引用对象的执行权限。
(3)存储过程允许用户模块化设计程序,极大地提高了程序设计的效率。例如,存储过程创建之后,可以在程序中任意调用,提高程序的设计效率、提高了应用程序的可维护性。
(4)存储过程可以大大减少网络通信流量,这是一条非常重要的使用存储过程的原因。

存储过程的类型
在SQL Server系统中,提供3种基本存储过程类型:
(1)用户定义的存储过程
(2)扩展存储过程
(3)系统存储过程
除此之外,还有临时存储过程、远程存储过程等,各自起着不同的作用。

创建存储过程 & 调用(执行存储过程)

CREATE PROCEDURE <存储过程名>
AS
	BEGIN
		<命令语句1>
		<命令语句>
    END 

执行存储过程

EXECUTE  <存储过程名>

无参数的存储过程👇

/**利用Transact-SQL语句创建1个无参数的存储过程,
该存储过程用于查询“高等教育出版社”出版的图书信息,
存储过程的名称为“getBookInfo_publisher_0601”。*/
create proc getBookInfo_0601
as 
	select 图书信息.* from 图书信息 join 出版社 on 图书信息.出版社 = 出版社.出版社ID
	where 出版社名称 = '高等教育出版社'

使用输入参数的准则👇

若要定义接受参数的存储过程,应在CREATE PROCEDURE语句中声明参数。使用输入参数时,应考虑以下准则:
(1)根据情况为参数提供默认值。如果定义了默认值,则用户无需为该参数指定值即可执行存储过程。
(2)在存储过程的开头验证所有传入的参数值,以尽早查出缺少的值和无效值。
使用参数默认值:
(1)执行存储过程时,没有为参数指定任何值。
(2)DEFAULT关键字指定为参数的值。

/*创建1个带输入参数的存储过程,该存储过程用于查询“高等教育出版
社”出版的有关“数据库”方面的图书信息,存储过程的名称为“getBookInfo_0602”*/
create proc getBookInfo_0602 
@publishName varchar(50) = '高等教育出版社', @bookName varchar(100) = '数据库'	--要创建变量,可以在变量后面赋默认参数
as 
begin	--begin 和 end 相当于 "(" 和 ")" 
	select 图书信息.* from 图书信息 join 出版社 on 图书信息.出版社 = 出版社.出版社ID
	where 出版社名称 = @publishName and 图书名称 like '%'+@bookName+'%'
end

--有了存储过程这一模块化的设计,可以更加简洁的查询数据👇
exec getBookInfo_0602 '高等教育出版社','数据库'	--简写的写法,变量的顺序必须对应变量创建时的顺序
execute getBookInfo_0602 @publishName = '高等教育出版社',@bookName = '数据库'	--这种写法的变量顺序可以随意

Exec getBookInfo_0602 --有了默认参数时,此句可执行

带输入参数和输出参数的存储过程👇

输出参数和返回值:
通过使用输出参数和返回值,存储过程可将信息返回给进行调用的存储过程和客户端。

/*创建一个带输入参数和输出参数的存储过程,
该存储过程用于根据读者类型的编号获取对应的“限借数量”和“限借期限”
存储过程的名称为“getNum_Limit”
*/
create procedure getNum_Limit
	@readerTypeId char(2),	--不写的默认是输入参数
	@limitedNum smallint output,	--output表示输出参数,是语法规则必须遵守
	@limitedDay smallint out	--output可简写为out
as 
	select @limitedNum = 限借数量, @limitedDay = 限借期限 from 读者类型
	where 读者类型编号 = @readerTypeId
	
--测试案例👇
declare @p1 smallint, @p2 smallint --定义两个输出参数
execute getNum_Limit '01' , @p1 out, @p2 out	--这里要加上output区分输入输出参数
print '限借数量为:' + ltrim(str(@p1)) + '本,限借期限为:' + ltrim(str(@p2)) + '天'	
--ltrim函数用于去除字符串左边的空格
--(1)创建1个存储过程,用于查询“石磊”所借图书信息,存储过程的名称为“proc_1”
create procedure proc_1
as 
	select 图书信息.* from 图书信息 join 藏书信息 on 图书信息.ISBN编号 = 藏书信息.ISBN编号
	join 图书借阅 on 藏书信息.图书编号 = 图书借阅.图书编号
	join 借书证 on 图书借阅.借书证编号 = 借书证.借书证编号
	where 姓名 = '石磊'

exec proc_1

--(2)创建1个存储过程用于查询某用户所借的某类图书的图书信息,存储过程的名称为“proc_2”
create procedure proc_2
	@userName varchar(20),
	@bookTypeName varchar(50)
as
	select 图书信息.* from 图书信息 join 藏书信息 on 图书信息.ISBN编号 = 藏书信息.ISBN编号
	join 图书借阅 on 藏书信息.图书编号 = 图书借阅.图书编号
	join 借书证 on 图书借阅.借书证编号 = 借书证.借书证编号
	join 图书类型 on 图书信息.图书类型 = 图书类型.图书类型代号
	where 姓名 = @userName and 图书类型名称 like '%' + @bookTypeName +'%'
exec proc_2 '石磊','工业'

--(3)创建1个存储过程,用于从“图书信息”数据表中根据指定的出版社简称(例如“高教”)
--或者出版社全称(例如“高等教育出版社”)获取所有该出版社的图书数量和总金额
create procedure proc_4 
	@publish varchar(50),
	@bookNum smallint out,
	@totalMoney float out
as
	select @bookNum = sum(总藏书量),@totalMoney = sum(价格*总藏书量) from 图书信息 join 出版社 on 图书信息.出版社 = 出版社.出版社ID
	join 藏书信息 on 图书信息.ISBN编号 = 藏书信息.ISBN编号
	where 出版社简称 like '%'+@publish+'%' or 出版社名称 like '%'+@publish+'%'

declare @p1 smallint, @p2 float
exec proc_4 '高数', @p1 out, @p2 out
print '高教出版社的图书数量为:' + ltrim(str(@p1)) + '本,总金额为:' + ltrim(str(@p2)) + '元'
查看存储过程:sp_help 存储过程名
删除存储过程:drop procedure 存储过程名

触发器

触发器是一种特殊类型的存储过程,包括了大量的T-SQL语句。但是触发器又与存储过程不同,例如存储过程可以由用户直接调用执行,但是触发器不能被直接调用执行,只能自动执行。
顾名思义触发器就是在执行SQL语句时时实现动作的自动触发

两个特殊的表

当触发器激发对INSERT,DELETE,或UPDATE语句的响应时,两个特殊的表被创建:插入和删除表:
(1)inserted表包含插入在触发器表中的所有记录的拷贝.
(2)deleted表包含了已从触发器表中被删除的所有记录。

分类:DML触发器和DDL触发器
DML触发器也有两类:
(1) AFTER触发器。该触发器在执INSERT, UPDATE, DELETE语句的之后执行。
(2)INSTEAD OF触发器,该触发器替代常规触发操作执行,还可以在基于一个或多个基表的视图上定义。

创建触发器

CREATE  TRIGGER   触发器名称
     ON  {table | view}
     {FOR |AFTER| INSTEAD OF|}
     {[INSTERT]|[UPDATE]|[DELETE]}
AS
	{sql_statement}
--创建1个命名为“borrow_insert”的DML触发器,当向“图书借阅”
--数据表插入1条借阅记录时,返回1条提示信息“已成功插入1条记录”。
create trigger borrow_insert on 图书借阅
after insert 
as 
	print '已成功插入1条记录'


--创建1个命名为“booktype_update”的DML触发器,防止用户修改
--“图书类型”数据表中的“图书类型代号”。
create trigger booktype_update on 图书类型
instead of update
as 
begin 
	if update(图书类型代号)
	begin
		print '不能修改“图书类型”数据表中的“图书类型代号”'
		rollback--“回滚”
	end
end

--在图书管理数据库的“图书借阅”数据表中创建1个触发器,当读者
--借出1本图书时,对应的“藏书信息”数据表的“馆内剩余”字段值
--也同步更新。(分别使用after和instead of完成)
create trigger tri_2 on 图书借阅
after insert
as
	update 藏书信息 set 馆内剩余 = 馆内剩余 - 1 where 图书编号 = (select 图书编号 from inserted)--inserterd表包含插入在触发器表中的所有记录的拷贝.

--测试👇
insert into 图书借阅 values('0016588','TP7111188365',1,getdate(),'2022-5-1','珠江','珠江',1)
select * from 图书借阅

disable trigger borrow_insert on 图书借阅--禁用“图书借阅”表的触发器
enable trigger borrow_insert on 图书借阅--禁用“图书借阅”表的触发器

--创建1个DDL触发器,用于防止用户删除或更改bookDB数据库中的任一数据表。
create trigger tri_3 on database
after drop_table, alter_table
as
begin
   Print '不能删除或修改该数据表'
   Rollback
end
--创建1个命名为“booktype_delete”的DML触发器,该触发器实现以下功能:
--限制用户删除“图书类型”数据表中的记录,当用户删除时出现“不能删除图书类型数据表中的记录”的--提示信息。
create trigger tri_3
on 图书类型
instead of delete
as
	print '不能删除图书类型数据表中的记录'


--为“借阅者”表添加1个触发器,当将“学生”的借阅者类型修改为
--“教师”时提示不能修改。(注意:学生改为其他非教师可以,非学生改为教师也可以)
--还没有借阅者表,所以先创建借阅者表
select *, '教师' as 借阅者类型 into 借阅者 from 教师
union
select *, '学生' from 学生

create trigger tri_4 on 借阅者
after update
as
begin
	if update(借阅者类型)
	begin
		declare @oldType varchar(50), @newType varchar(50)
		select @oldType = 借阅者类型 from deleted
		select @newType = 借阅者类型 from inserted
		if(@oldType = '学生' and @newType = '教师')
		begin
			print '不能将“学生”的借阅者类型修改为“教师”'
			rollback --因为是after,所以要回滚
		end
	end
end

--为“出版社”表添加1个触发器——publish_delete,当删除某出版社
--时自动检查其出版的图书信息是否存在,若存在,先将其藏书信息和图书信息删除
/*(注意:由于外键影响,某藏书记录存在,则无法删除与其关联的图书记录;
某图书记录存在,则无法删除与其关联的出版社记录。按藏书信息----图书信息
----出版社的顺序则可实现删除)
*/
create trigger publish_delete on 出版社
instead of delete
as
begin
	declare @pid int
	select @pid = 出版社ID from deleted
	if exists(select * from 图书信息 where 出版社 = @pid)
	begin
		delete from 藏书信息 where ISBN编号 in(select ISBN编号 from 图书信息 where 出版社 = @pid)
		delete from 图书信息 where 出版社 = @pid
		delete from 出版社 where 出版社ID = @pid
	end
	else
		delete from 出版社 where 出版社ID = @pid
end

T-SQL应用编程

SQL语言的主要功能就是同各种数据库建立联系并进行交互。按照ANSI(美国国家标准协会)的规定,SQL被作为关系型数据库管理系统的标准语言。
T-SQL语言是Microsoft公司在SQL Server数据库管理系统中SQL的实现,主要用于关系数据的操作,是与SQL Server交流的语言。

T-SQL语言的编程功能:

基本功能:
数据定义语言(Data Definition Language,DDL)功能;
数据操纵语言(Data Manipulation Language,DML)功能;
数据控制语言(Data Control Language,DCL)功能;
事务管理语言(Transact Management Language,TML)功能;
数据字典DD及其应用功能。
基本扩展功能:
程序流程控制结构(顺序-选择-循环)
此外包括: T-SQL附加的语言元素的辅助语句的操作、标识、理解和使用,并加入局部变量和系统变量等。
附加的语言元素包括: 标识符、常量、变量、运算符、表达式、数据类型、函数、流程控制语句、错误处理语言、注释等元素。

标识符命名规则

(1)标识符组成是字母、数字、下划线、@(专用) 、#和$ ,其中字母可以是大小写英文,也可以是来自其他语言的字符。
(2)标识符的首字符不允许是数字或$符号。
(3)标识符不允许使用SQL的保留字,如命令名、函数名等。
(4)标识符内不允许有空格和特殊字符,如?、%、&、*等。
(5)标识符长度不超过128字节。

当一定要使用保留字命名时,需要使用界定标识符,界定标识符也叫分隔标识符(定界符)是使用[ ]、‘ ’或””等起到分隔作用的符号限定的标识符
带分隔符的标识符用于下列情况:在对象名称或其组成部分中使用保留字时;使用未列为限定标识符的字符时。

常量

请添加图片描述

局部变量

由用户定义,其作用域为其定义域,可以用SET语句改变其值

定义局部变量

DECLARE @变量名 数据类型,…

说明:(1)局部变量必须由@开头。
(2)局部变量不能是 text、ntext 或 image 数据类型。
(3)局部变量必须先声明(定义),然后在SQL语句中使用,默认初值NULL。

局部变量赋值

SET @变量名=表达式
或
SELECT @变量名=表达式/SELECT @变量名=输出值 FROM 表 where语句
或
SELECT @变量1=表达式1,@变量2=表达式2,…,@变量n=表达式n]

全局变量

系统全局变量是SQL Server系统定义(提供并赋值)的变量,常用于跟踪服务器范围和特定会话期间的信息,用户只能显示和读取,不能修改
记录SQL Server服务器活动状态的一组数据,系统提供33个全局变量,常用的全局变量如下
请添加图片描述

set语句

set语句用于设定用户执行T-SQL命令时SQL Server处理选项
SET 运行/处理环境(方式) [ON/OFF/值]

设置显示/隐藏受T-SQL语句影响的行数信息的语法
SET NOCOUNT (ON|OFF)

select语句

SELECT作为输出使用时的语法
SELECT 表达式1[,表达式2,…,表达式n]

SQL Server还支持非标准的赋值SELECT语句,允许使用单个语句查询数据并分配给来自同一行的多个值给多个变量👇

--将订单编号orderId为3001的顾客的姓和名,赋值给两个变量。
DECLARE @firstname AS NVARCHAR(10), @lastname AS NVARCHAR(20);
SELECT
  @firstname = firstname,--分配给来自同一行的多个值给多个变量
  @lastname  = lastname
FROM 订单信息表
WHERE orderId =3001;

print语句

输出语句PRINT主要用于在指定设备上输出字符型信息,可以输出的数据类型只有:char、nchar、varchar、nvarchar以及全局变量@@VERSION等。
PRINT语句格式为:

PRINT <表达式>
或
PRINT 'any ASCII text' | @local_variable | @@FUNCTION | string_expr

顺序结构

--查询借书最多的学生的姓名和借书数量,并用两种方式输出(带上单位“本”)
declare @name varchar(50), @count int
select @name = 姓名,@count = count(*) from 图书借阅 join 借书证 on 图书借阅.借书证编号 = 借书证.借书证编号
group by 姓名 order by count(*)
select @name, ltrim(str(@count)) + '本'
print @name + '借书' + ltrim(str(@count)) + '本'

--查询学生中没有借书的人数并输出(有多种方法)
declare @n int, @n1 int, @n2 int
select @n = count(*) from 学生
select @n1 = count(*) from 学生 where exists(
select * from 图书借阅 join 借书证 on 图书借阅.借书证编号 = 借书证.借书证编号
where 学生.学号 = 借书证.借阅者编号)
select @n2 = @n - @n1
print '学生中没有借书的人数为' + ltrim(str(@n2)) + '人'

选择结构

if-else

IF  <逻辑表达式>
    <语句块1>
ELSE
    <语句块2>
// else语句可有可无
--判断今天是否是一年的最后一天
IF YEAR(SYSDATETIME( )) < > YEAR(DATEADD(day, 1,SYSDATETIME( )))
/* SYSDATETIME( )函数可获得当前系统时间*/
  PRINT ‘今天是一年的最后一天!’
ELSE
  PRINT ‘今天不是一年的最后一天!’
GO

简单case

CASE <字段名/变量名表达式>
    WHEN <逻辑表达式> THEN <结果表达式>
     ...
     [ELSE <其他结果表达式>]
END
--显示付费方式表中用户的付费方式
SELECT orderD.订单姓名,  payT.类型编号 as 类型, 付费方式=
    CASE 类型
WHEN 1 THEN '支付宝'
WHEN 2 THEN '网上银行'
WHEN 3 THEN '货到付款'
WHEN 4 THEN '他人代付'
    ELSE  '其他'
    END
  FROM 订单详情表 orderD, 付费方式表 payT	--这里的英文名是给表起别名
  WHERE  orderD.付费方式= payT.类型编号;

搜索式case

CASE           
    WHEN <逻辑表达式> THEN <结果表达式>
      ...
     [ELSE <其他结果表达式> ]
 END
SELECT orderD.订单姓名,  payT.类型编号 as 类型, 付费方式=
CASE 
WHEN 付费方式=1 THEN '支付宝'
WHEN 付费方式=2 THEN '网上银行'
WHEN 付费方式=3 THEN '货到付款'
WHEN 付费方式=4 THEN '他人代付'
ELSE '其他'
END
FROM 订单详情表 orderD,付费方式表 payT
WHERE  orderD.付费方式= payT.类型编号;

练习

--查询“石磊”同学是否借阅了图书,如果已借阅图书则显示其借阅的总数量。
declare @num int
select @num = count(*) from 图书借阅,借书证 
where 图书借阅.借书证编号 = 借书证.借书证编号 and 借书证.姓名 = '石磊'
if(@num>0)
	print '石磊借书:'+ ltrim(str(@num)) +'本'
else
	print'石磊没有借书'
	
--“图书管理系统”中的“图书状态”一般有四种:借出、续借、损坏、
--丢失,分别用0、1、2、3表示。查询所有图书借阅情况,输出借书证编号、
--图书编号、借出数量和图书状态(分别用借出、续借、损坏、丢失描述)4列数据。
select 借书证编号,图书编号,借出数量,图书状态=
	case 图书状态
		when 0 then '借出'
		when 1 then '续借'
		when 2 then '损坏'
		when 3 then '丢失'
	else '其他'
	end
from 图书借阅

--查询“文静”同学的借书证能否正常借书(已借数量<限借数量)。若能正常借书,
--则她借阅了图书编号为“TP7040273144”的图书。在“图书借阅”数据表中添加
--借阅记录,并修改“藏书信息”数据表的“馆内剩余”数量。
declare @count int,@limitcount int,@name varchar(50),@boorowNo char(12)
set @name = '文静'
set @boorowNo = 'TP7040273144'
--获得已借书量
select @count = count(*) from 图书借阅,借书证
where 图书借阅.借书证编号 = 借书证.借书证编号 and 姓名 = @name
--获得限制借书量
select @limitcount = 限借数量 from 读者类型 where 读者类型编号 = (
select 读者类型 from 借书证 where 姓名 = @name)
if(@count<@limitcount)
begin
	--插入数据
	insert into 图书借阅
	values((select 借书证编号 from 借书证 where 姓名 = @name)
			,@boorowNo,1,GETDATE(),2022-6-18,'白云','白云',0)
	--修改数据
	update 藏书信息
	set 馆内剩余 = (select 馆内剩余 from 藏书信息 where 图书编号 = @boorowNo)-1
	where 图书编号 = @boorowNo
end
	--提示不能借书
	print '达到借书限制数量'

循环结构

  WHILE <逻辑表达式>
		{ SQL语句| 语句块}
		[BREAK]
		{ SQL语句| 语句块}
		[CONTINUE]
--统计未来100年中闰年的年份个数
declare @y int,@count int
set @count = 0
set @y = 2023
while @y<2123
begin
	if (@y%4=0 and @y%100!=0) or @y%400=0
		begin
			set @count = @count +1
		end
	set @y = @y+1
end
print @count

--创建一个读者表(读者编号, 读者姓名, 部门),再为这个表填
--充读者编号,其他字段留空
--读者编号从“200101”-“200200”,遇到整十数跳过
set nocount on
if OBJECT_ID('读者','u') is not null drop table 读者
create table 读者(
	读者编号 int,
	读者姓名 varchar(20),
	部门 varchar(20)	
)
go
declare @No int
set @No = 200100
while(@No<200200)
begin
	set @No = @No+1
	if(@No%10=0)
		continue
	else
		insert into 读者(读者编号)
		values(@No)
end

select * from 读者

goto(很少用)

label:<程序行>
GOTO  label

等待语句

等待语句是利用WAITFOR命令产生一个延时,使存储过程或程序等待或直到一个特定时间片后继续执行,语法结构:

WAITFOR DELAY '<时间长度>' | TIME '<时间点>‘

DELAY指SQL Server等候的时间长度,最长为24小时,TIME指SQL Server延时至当天何时
时间长度和时间点的格式都为:hh:mm:ss

返回语句

返回语句是利用RETURN命令,使一个存储过程或程序退出并返回到调用它的程序中。其语法结构如下:

RETURN [<整型表达式>]

说明:使用RETURN命令只可以返回一个整型值给其调用程序,若想返回其他类型的数据,必须使用输出参数。
调用存储过程时,返回值信息的含义。
请添加图片描述

函数

聚合函数

使用一组特定输入值(数值型)调用,聚合函数总是返回同类型的值。
请添加图片描述

数学函数

请添加图片描述

字符函数

请添加图片描述

日期时间函数

请添加图片描述

请添加图片描述

自定义函数

标量值自定义函数

其返回的值类型为除text、ntext、image、cursor、timestamp和table类型外的其他数据类型

CREATE FUNCTION 函数名 (@参数名 参数类型 [ =default ],… )
RETURNS 数据类型
[WITH ENCRYPTION]
[AS]
    BEGIN
         可以在这里定义变量
         函数体
         RETURN 变量
     END
--创建一个“标量值”函数getBookTypeName,用于从“图书类型”数据表中根据指定的“图书类型代号”获取“图书类型名称”
Create Function getBookTypeName(@bookTypeNum varchar(2))
Returns varchar(50)
As
   Begin
        Declare @bookTypeName varchar(50)
        Select @bookTypeName=图书类型名称 From 图书类型
               Where 图书类型代号=@bookTypeNum 
        Return @bookTypeName
    End
--调用
Select dbo.getBookTypeName(‘T’) AS ‘图书类型’	--带上dbo才能被识别为自定义函数

内联表值自定义函数

返回一个表,RETURN子句包含的SELECT语句将数据从数据库中筛选出形成一个表

CREATE FUNCTION 函数名 (@参数名 参数类型 [ =default ],… ) 
RETURNS TABLE
[WITH ENCRYPTION]
[AS]
     RETURN 变量
--创建1个内联表值函数getBorrow,用于从“图书借阅”数据表中根据指定的“借书证编号”获取对应的借阅信息
Create Function getBorrow(@cardNum varchar(7))
Returns Table
With Encryption
As
  Return Select * From 图书借阅 Where 借书证编号=@cardNum
--调用
Select * From dbo.getBorrow('0016584')

多语句表值自定义函数

标量型和内联表值型函数的结合体,返回值的表中的数据是由函数体中的语句插入的,其可以进行多次查询,对数据进行多次筛选与合并,弥补了内联表值自定义函数的不足。

--创建一个函数,用于判断某出版社是否存在,若存在,
--则获取该出版社出版的图书种数和图书总金额,若不存在,
--则显示“XXXX出版社不存在”字样。
create function func_demo(@pubName varchar(50))
returns varchar(50)
as
begin 
	declare @res varchar(50), @count int, @totalmoney float
	if exists(select * from 出版社 where 出版社名称 = @pubName)
	begin
		select @count = count(*), @totalmoney = sum(价格) from 图书信息 where 出版社 = (
			select 出版社id from 出版社 where 出版社名称 = @pubName)
		set @res = str(@count)+str(@totalmoney)
	end
	else
		set @res = @pubName + '不存在'
	return @res
end

print dbo.func_demo('清华大学出版社')


--创建1个函数,用于查询某位借阅者(姓名)借阅的某方面
--的图书信息,输出借阅者的姓名,读者类型,图书名称和作者。
create function getInformation(@name varchar(40))
returns table
as
	return select 借书证.姓名,读者类型,图书名称,作者 from 借书证
	join 图书借阅 on 图书借阅.借书证编号 = 借书证.借书证编号
	join 藏书信息 on 图书借阅.图书编号 = 藏书信息.图书编号
	join 图书信息 on 图书信息.ISBN编号 = 藏书信息.ISBN编号
	and 借书证.姓名 = @name

select * from dbo.getInformation('石磊')

批处理、脚本及事务

批处理

批处理是指一次性的T-SQL语句组的执行处理,SQL Server将批处理编译成一个可执行单元,称为执行计划,若批处理中的某条语句编译出错,则无法执行。
GO 作为批处理命令的结束标志,当编译器读取到 GO 时,会将 GO 前的所有语句当作一个批处理,并将这些语句打包发送给服务器。GO 语句本身不是T-SQL语句的组成部分,只是一个表示批处理结束的前端指令,GO 后面加上数字表示多次进行批处理
注意事项:
1️⃣ 一次只能限于一个处理,增删改及存储过程和触发器等.
2️⃣ 批处理中删除一个对象后,在此批处理中无法再次引用此对象。
3️⃣ 不可将规则和默认值绑定到表字段/自定义字段上后,不允许在定义一个check约束后,不能在修改表中一字段名后,不能在使用set语句设置选项后,不能在同一批处理中对该字段/check约束/字段名/选项进行使用。
4️⃣ 若批处理中第一个语句是执行某个存储过程的execute语句,
则execute关键字可省略.若不是第一个语句,则必须写上👇

proc_name
Select语句	--正确,execute可省略

Select语句
proc_name	--错误,execute只有在首句时可以省略

指定批处理的方法

(1) 应用程序作为一个执行单元的所有SQL语句构成一个批处理,并生成单个执行计划。
(2) 存储过程或触发器内的所有语句构成一个批处理,每个存储过程或触发器都编译为一个执行计划。
(3) 由EXECUTE语句执行的字符串是一个批处理,并编译为一个执行计划。
(4) 由sp_executesql存储过程执行的字符串是一个批处理,并编译为一个执行计划。
说明:若应用程序发出的批处理过程中含有EXECUTE语句,已执行字符串或存储过程的执行计划将和包含EXECUTE语句的执行计划分开执行。

批处理的执行、结束和退出

1)批处理的执行:EXECUTE
2)批处理结束语句:GO,作为批处理的结束标志。
3)批处理退出语句:RETURN [整型表达式]
说明:当用于存储过程时,RETURN不能返回空值。若return语句未指定值,则存储过程的返回值是0。

脚本

脚本是存储在文件中一系列T-SQL语句。是一系列顺序提交的批(处理),脚本文件扩展名为.sql。脚本可直接在查询分析器等工具中输入并执行,也可以保存文件中,再由查询分析器等工具执行。可包含批处理,GO作为批处理结束语句,若脚本中无GO语句,则作为单个批处理。
脚本的用途主要有两个方面:
(1)在服务器上创建一个数据库的步骤,存储在脚本文件中
(2)将语句保存为脚本文件,从一计算机传递到另一计算机,可以方便地使两台计算机执行同样操作。

事务

事务的定义. 事务(Transaction)是完成一个应用处理的最小单元,作为单个逻辑工作单元由数据库操作的语句组成.
一个事务可以是一组(句)SQL语句或整个程序,一个应用程序可以包括多个事务。
在SQL语言中,定义事务的语句有3条:

BEGIN TRANSACTION	--事务的开始
COMMIT			--事务的提交
ROLLBACK			--回滚

事务的特征(ACID准则)

(1) 原子性(Atomic)。各事务为不可分割的工作单位,执行时应遵守“要么不做,要么全做”的原则,不允许事务 部分完成(即存在一句失败则回滚到最初)
(2) 一致性(Consistency)。事务对数据库的作用是使数据库从一个一致状态转变到另一个一致状态。数据库的一致状态是指数据库中的数据满足完整性约束。
(3) 隔离性(Isolation)。若多个事务并行执行,应如同各事务独立执行一样,一个事务的执行不能受其他事务干扰。并发控制就是为了保证事务间的隔离性.
(4) 持久性(Durability)。事务是一个恢复单元,一个事务一旦提交,对数据库中数据的改变就是持久的,即使数据库因故障而受到破坏,DBMS也应当可以恢复。

/*白雪向“书香”书店订购了一批图书,需要支付的书款金额为7800元,
支付的书款通过中国银行转账,“书香”书店的银行账号为
“4701455-0188-039560-8”,付款账号为“4701455-0001-032780-1”,
两个账号都允许不透支,即余额不小于0。要求转账过程中不能出现错误,
而且不管是否转账成功,都支付1%的手续费。应用事务实现以上操作。
*/
create table 银行账户(
	账户ID int identity,
	账户名称 varchar(60),
	账号 varchar(30),
	余额 money,
	负责人印章 varchar(50)
)
insert into 银行账户 values
('书香','4701455-0188-039560-8',2200,'小书'),
('白雪','4701455-0001-032780-1',9878,'小雪')

select * from 银行账户

declare @pay money, @scale float, @error1 int, @error2 int
select @pay = 7800, @scale = 0.01, @error1 = 0, @error2 = 0	--付款7800元,手续费0.01%
begin transaction	--事务的开始
--1、扣手续费
	update 银行账户 set 余额 = 余额 - @pay + @scale where 账号 = '4701455-0001-032780-1'
	set @error1 = @error1 + @@ERROR
	save transaction flag	--设置回滚标记,若第二步或第三部失败,则事务回滚到此句
	--2、扣款
	update 银行账户 set 余额 = 余额 - @pay where 账号 = '4701455-0001-032780-1'
	set @error2 = @error2 + @@ERROR
	--3、打款
	update 银行账户 set 余额 = 余额 + @pay where 账号 = '4701455-0188-039560-8'
	set @error2 = @error2 + @@ERROR
	if @error1<>0	--如果第一步失败,则回滚到最初
	begin
		rollback transaction
		print '交易失败,事务回滚到最初'
	end
	else			
		if @error2<>0--如果第二步或第三步失败,则回滚到flag的位置
		begin
			rollback transaction flag
			print '交易失败,但是依然扣除手续费'
		end
		else		--如果三个步骤都成功,则提交事务
		begin
			commit transaction
			print '交易成功'
		end

数据库安全

介绍

三个方面

数据安全是指以保护措施确保数据的保密性、完整性、可用性、可控性和可审查性(5个安全属性),防止数据被非授权访问、泄露、更改、破坏和控制。
**数据库安全(DataBase Security)**是指采取各种安全措施对数据库及其相关文件和数据进行保护,其实质是保证系统运行安全和系统信息安全。
**数据库系统安全(DataBase System Security)**是指为数据库系统采取的安全保护措施,防止系统软件和其中数据不遭到破坏、更改和泄漏。

数据库安全机制及措施

(1)用户认证(身份认证)
数据库系统为了保护授权用户对数据库的操作,提供了用户身份识别与认证机制。用户认证即用户标识与鉴别,是系统提供的最外层安全保护措施。其方法是由系统提供一定的方式让用户标识其用户名或身份,每次用户登录系统时,由系统进行核对,通过鉴别后提供使用权限。已获得使用权的用户若要使用数据库,DBMS还要进行用户认证。由于数据库用户的安全等级是不同的,因此分配给他们的权限也是不一样的
(2)访问控制
数据库安全性主要依靠DBMS的访问控制机制。通过数据库系统的访问控制机制,可以对已登录系统的用户的访问控制,是数据库安全系统中的核心技术,也是最有效的安全手段。
①授权。DBMS提供了功能强大的授权机制,可给用户授予各种不同对象(表、视图、存储过程等)的不同使用权限(如Select、update、insert、delete等)。
②角色。是被命名的一组与数据库操作相关的权限,即一组相关权限的集合。可为一组相同权限的用户创建一个角色。使用角色管理数据库权限,可简化授权的过程。

(3)视图隔离
视图是从基表(或视图)导出的一个不含有数据的虚表。是数据库系统提供给用户以多种角度观察数据库中数据的重要机制,数据库中只存放视图的定义,而不存放视图对应的数据,数据仍存放在原来的基本表中。
视图提供了一种简便访问数据方法,在授予用户对特定视图的访问权限时,该权限只用于在该视图中定义的数据项,而不是用于视图对应的完整基本表。

(4)数据加密
为了有效防止数据在传输和使用过程中被窃取或泄密,必须对数据进行加密。
(5)审计
审计功能是数据库安全的最后一道防线。审计指记录数据库操作和事件的过程。审计记录可以记载用户所使用的系统权限、频率、登录的用户数、会话平均持续时间、使用的命令,以及其他有关操作和事件。通过审计功能可将用户对数据库的所有操作自动记录下来,存放在日志文件中。

目的

(1)保密性
数据的保密性是指不允许未经授权或越权的用户存取或访问数据。
可利用对用户的认证与鉴别、权限管理、存取控制、数据库与数据加密、推理控制等措施进行实现。
①用户标识与鉴别。②存取控制。③数据库加密。④审计。⑤备份与恢复。⑥推理控制与隐私保护。
(2)完整性
数据的完整主要包括物理完整性和逻辑完整性。
①物理完整性。指保证数据库的数据不受物理故障(如硬件故障或掉电等)的影响,并有可能在灾难性毁坏时重建和恢复数据库。
②逻辑完整性。指对数据库逻辑结构的保护,包括数据语义与操作完整性。前者主要指数据存取在逻辑上满足完整性约束,后者主要指在并发事务处理过程中保证数据的逻辑一致性。
(3)可用性
数据的可用性是指在授权用户对数据库中数据正常操作的同时,保证系统的运行效率,并提供用户友好的人机交互。
操作系统中的对象一般情况下是文件,而数据库支持的应用要求更为精细。通常较完整的数据库对数据安全性采取以下措施:
①将数据库中需要保护的部分与其他部分进行隔离。
②采用授权规则,如账户、口令和权限控制等访问控制方法。
③对数据进行加密后存储于数据库中。

(体现在服务器上的)SQL Serve 安全机制

SQL Server的安全控制策略是一个层次结构系统的集合,只在满足上一层系统的安全性要求后,才可进入下一层。
在这里插入图片描述
下面的内容只涉及到后三层安全机制:
(1)操作系统级的安全性。
(2)SQL Server 级的安全性。
(3)数据库级的安全性。

(用户操作时涉及到的)身份认证和访问控制

用户管理

当用户在客户端向服务器端发送操作请求时,首先需要对该用户进行身份认证,并确认该操作请求没有被“重放”、篡改,确保该用户的合法性,以及请求的真实性。从技术角度,可以提供多种方法实现安全需求,如基于时间戳、随机数等机制可以抵抗操作请求的重放,MAC码、哈希函数等技术可以用于检测操作请求是否被篡改。

身份认证

在开放共享的网络环境下,访问网络数据库系统的用户必须要求进行身份认证,以防非法用户访问。在非网络数据库管理系统中,身份认证有系统登录、数据库连接和数据库对象使用三级。在网络环境下,网络数据库管理系统分为两级:认证用户身份对数据库访问权限;认证用户对数据库对象的访问权限。
Windows身份认证模式和混合模式。
Windows身份认证模式会启用Windows身份认证并禁用SQL Server身份认证。
混合模式会同时启用Windows身份认证和SQL Server身份认证。
Windows身份认证始终可用,并且无法禁用。

SQL Server身份认证

(1)配置身份认证模式
如果在安装过程中选择混合模式身份认证,则必须为名为sa的内置SQL系统管理员帐户提供一个强密码并确认该密码。
如果安装过程中选择Windows身份认证,则安装程序会为SQL身份认证创建sa帐户,但会禁用该帐户。
(2)密码策略
供SQL Server登录名使用的密码策略有3种。
①用户在下次登录时必须更改密码。要求用户在下次连接时更改密码。
②强制密码过期。对SQL登录名强制实施计算机的密码最长使用期限策略。
③强制实施密码策略。对SQL Server登录名强制实施计算机的Windows密码策略,包括密码长度和密码复杂性。

访问控制

访问控制策略、用户身份、数据库资源和访问行为构成网络数据库访问控制模型。其核心是:此策略将用户、特定数据库资源和用户对资源的访问行为(许可或拒绝)紧密联系。

审计追踪

身份认证和访问控制是目前网络信息系统中普遍使用的安全性方法,但没有一种可行的方法彻底解决合法用户在通过身份认证后滥用特权的问题。因而,网络数据库中对合法用户或合法请求的审计追踪可以自动对网络数据库的操作记录在审计日志中,以此来监视各用户及操作请求对数据库的操作。

(体现在用户操作上的)SQL Server 安全机制

SQL Server 采用的安全机制主要分为如下5个等级:客户机的安全机制、网络传输的安全机制、数据库服务器级别的安全机制、数据库级别的安全机制、数据库对象级别的安全机制。
用户访问SQL Server 数据库及对象时,需要依次经过上述的5个等级的安全校验,用户只有通过前面的安全校验后,才可以进入下一个安全校验。
下面的实操只涉及到后三个安全机制

实操(图形界面操作和命令操作)

登录名

图形界面操作
(1)查看图书管理数据库“bookDB”所在服务器的登录模式。
(2)将服务器的登录模式由“Windows身份验证模式”更改为“SQL Server和Windows身份验证模式”——右键服务器,选择属性-安全性。。。。设置完成后要右键服务器,选择“重新启动”
(3)在Windows操作系统中新增1个Windows用户(WinUser)。
(4)在SQL Server中创建Windows身份验证的登录名“服务器名\ WinUser”。且将SQL Server的登录账户映射到Windows用户WinUser 。右键->服务器-安全性-登录名,选择“新建登录名”,输入“机器名\Windows用户名”,在“常规”中“默认数据库”默认为“master”,如果改为其他数据库,则同时要在“用户映射”中选中对应的数据库,不选中则该用户名会登录失败(原因:登录同时会打开其默认数据库,要求要有该数据库的访问权限)
(5)尝试以WinUser用户身份(用户名为“服务器名\ WinUser”,)登录SQL Server 。(SQL Server会自动识别电脑当前登录到Windows用户,所以需要注销当前Windows用户,登录另外一个用户)
(6)以SQLUser01用户身份(登录名为“SQLUser01”)登录SQL Server ,试验该登录名对各个数据库的访问权限(结果是:默认的数据库bookDB可以访问,而其他的数据库则无法访问)
命令操作
分别使用DDL和命令方式在SQL Server 中创建SQL Server身份验证的登录名“SQLUser01”,密码为“abc_123”,默认数据库为bookDB。

--需要在有系统管理员权限的登录名创建的查询中才能操作成功
--DDL操作:
Create Login SQLUser02 With Password='abc_123',	--创建登录名
Default_database=bookdb

Drop login SQLUser02	--删除登录名
--系统存储过程操作:
Sp_addlogin 'login_name’, 'password’, 'default_db'	--创建登录名
Sp_droplogin 'login_name'	--删除登录名

用户

图形界面操作
在数据库“bookDB”中(有系统管理员权限的登录名创建的查询中)创建SQL Server身份验证的数据库用户账户“bookDB_SQLServer01”,并将其映射到登录名“SQLUser01”(映射的作用:登录该登录名同时会将该用户添加到对应的数据库下,数据库bookDB-安全性-右键用户,选择“新建用户”,在“常规”中输入用户名、登录名、默认架构不用填)
命令操作

--下拉列表中选中目标数据库
--DDL操作:
Create User 用户名 For Login 登录名	--创建用户并映射到登录名
With Default_schema=默认架构		--设置默认架构
Drop user 用户名					--删除用户
--系统存储过程操作:
Sp_grantdbaccess '登录名',' 用户名'	--创建用户并映射到登录名
Sp_revokedbaccess '用户名'		--删除用户

使用命令方式创建SQL Server身份验证的数据库用户账户bookDB_SQLServer02,并将用户账户“bookDB_SQLServer02”映射到登录名“SQLUser02”,默认架构为“dbo”。

--下拉列表中选中目标数据库
--DDL操作:
Create User bookDB_SQLServer02 For Login SQLUser02	--创建用户并映射到登录名
With Default_schema=dbo	
Drop user bookDB_SQLServer02 --删除用户

角色

注:固定的角色是系统自有的
(1)为SQL Server服务器登录名SQLUser02分配固定服务器角色sysadmin。(服务器角色决定了登录名的访问权限:右键->服务器-安全性-登录名,选择“属性”,在“服务器角色”中选择)
(2)为数据库用户“bookDB_SQLServer01”分配固定数据库角色db_owner。(数据库角色决定了在该数据库下该用户的访问权限:右键目标数据库-安全性-用户-目标用户,选择“属性”,在“成员身份”中选择)
(3)创建自定义角色“role_读者类型”,该角色只拥有对“读者类型”数据表的“选择”权限,并且将数据库用户“bookDB_SQLServer01”添加为该自定义角色的成员。(要在有权限的登录名下操作:右键目标数据库-安全性-数据库角色,选择“新建数据库角色”,填入角色名称,在“安全对象”中搜索“特点类型的所有对象”的“表”,选中“读者类型”表,在下方列表中授予“选择”权限并确定;右键数据库用户“bookDB_SQLServer01”属性,在“成员身份”中选择创建的角色 )
使用命令方式创建数据库角色

Sp_addrole '角色名'		--创建角色
Sp_droprole '角色名'		--删除角色

Sp_addrolemember '角色名', '用户名'		--将用户加入到角色中
Sp_droprolemember '角色名', '用户名'	--将用户从角色中删除

注意:多条语句之间用 go 连接

权限

请添加图片描述

(1)使用图形化界面给SQL Server服务器登录名“SQLUser01”授予创建数据库和更改登录名等操作权限。(右键目标服务器,进入属性-权限,在上方列表选中登录名,下方授予创建数据库和更改登录名操作权限,操作完成后该登录名便拥有创建数据库和更改登录名的权限)
(2)使用图形化界面给数据库用户账户“bookDB_SQLServer01”授予创建数据表的权限(右键目标数据库,进入属性-权限,在上方列表选中用户,在下方列表授予权限)
(3)使用图形化界面给数据库用户账户“bookDB_SQLServer01”授予对“bookDB”数据库中“图书类型”数据表的“插入、查看定义、更改、更新、删除、选择”等操作权限。(右键目标用户,进入属性,在“安全对象”中搜索“特点类型的所有对象”的“表”,选中“读者类型”表,在下方列表中授予对应的权限并确定 )

Grant DML权限 On 对象 To 用户名
Revoke DML权限 on 对象 from 用户名	--当要收回某用户拥有的权限(该权限是用户的而非角色授予给用户的)
Deny DML权限 on 对象 to 用户名		--当要收回某角色授予给该用户的权限(该用户的此权限是某角色授予给该用户的而非该用户本身拥有的)

Grant DDL权限To 用户名
revoke DDL权限 from 用户名
deny DDL权限To 用户名

以上的命令也可以对角色进行授权操作
(4)使用命令方式给数据库用户账户“bookDB_SQLServer01”授予对“bookDB”数据库中“出版社”数据表的“选择”权限。

Grant Select On 出版社 To bookDB_SQLServer01

(5)使用命令方式给数据库用户账户“bookDB_SQLServer01”授予使用“create view”语句的权限。

Grant Create View To bookDB_SQLServer01

综合练习

请添加图片描述
答案👇

--创建登录名
sp_addlogin 'zhang','111'
go
sp_addlogin 'wen','222'
go
sp_addlogin 'zhan','333'
go
sp_addlogin 'chen','444'
go

--创建用户
sp_grantdbaccess 'zhang','mrzhang'
go
sp_grantdbaccess 'wen','wmy'
go
sp_grantdbaccess 'zhan','zhangyue'
go
sp_grantdbaccess 'chen','chenwei'
go

--创建角色
sp_addrole 'teacher'
go
sp_addrole 'student'
go

--将用户添加到对应的角色中
sp_addrolemember 'db_owner','mrzhang'
go
sp_addrolemember 'teacher','mrzhang'
go
sp_addrolemember 'teacher','wmy'
go
sp_addrolemember 'student','zhanyue'
go
sp_addrolemember 'student','chenwei'
go

--授权
grant select,insert on 教师 to teacher
grant select,insert on 学生 to teaher
grant update 教师(职工编号,姓名) to teacher

grant select,insert on 学生 to student
grant update on 学生(姓名) to student

waitfor delay  '00:10:00'
revoke update 教师(职工编号,姓名) from teacher 

deny insert on 学生 to zhanyue
deny update on 学生(姓名) to zhanyue

数据备份与恢复

四种备份模式

(1)完整备份
(2)差异备份(即更新备份,将备份补充完整)
(3)事务日志备份
(4)文件或文件组备份

三种恢复模式

(1)大容量日志模式
大容量日志模式类似于完全模型,但简略地记录大多数大容量操作(例如,索引创建和大容量加载),完整地记录其他事务。
大容量日志恢复模式为大容量操作提供了更高的性能和最少的日志使用空间,常用作完整恢复模式的补充。

(2)完整模式
完整模式完整地记录了所有的事务,并保留所有的事务日志记录,直到对它们进行了备份为止。
在 SQL Server企业版中,完整恢复模式能使数据库恢复到故障时间点(假定在故障发生之后备份了日志尾部)。
如果数据文件损坏,则可以还原所有已提交的事务。正在进行的事务将回滚。

(3)简单模式
简单模式简略地记录大多数事务,所记录的信息只是为了确保在系统崩溃或还原数据备份之后数据库的一致性。
数据只能恢复到最新的完全数据库备份或差异备份的状态。
可用于小型或修改频率不高的数据库,但如果数据文件损坏,则数据损失表现会更高。
在这里插入图片描述

有了以上多种备份模式,该如何策划SQL Sever数据库的备份策略 ?

备份策略是用于描述何时使用何种备份类型的计划。例如,可以单独使用完整备份,也可以使用完整、差异备份相结合或其他任何一种有效的备份组合。
(1)完整备份
(2)完整兼差异备份
(3)完整兼事务日志备份
(4)完整、差异兼事务日志备份
(5)文件组备份

还原数据库的三种不同策略

举例1:数据库备份的时间线(时间从左往右):全1️⃣-差-全2️⃣-差1️⃣-差2️⃣-日1️⃣-日2️⃣-日3️⃣
1、还原完整数据库备份norecovery
从最近的一次完全备份开始。 即全2️⃣

1+2、还原差异数据库备份norecovery
1+如果最近一次完全备份之后还有差异备份,则恢复最后一个差异备份。即全2️⃣->差 2️⃣

1+2+3、还原事务日志备份并恢复数据库recovery
1+2+如果最后一个差异备份之后还有日志备份,则依次全部恢复。 即全2️⃣->差 2️⃣->日1️⃣->日2️⃣->日3️⃣

举例2:
例如,一个数据库使用以下操作进行备份:
每星期天晚上进行完全备份
从星期一到星期六在每晚9:00进行差异备份
星期一到星期六每天上午9:00至下午6:00间每小时进行一次日志备份

现假定在某个星期四上午11:05数据库被破坏,则可采用如下操作恢复数据库:
首先恢复上一个星期天晚上的完全备份
然后恢复前一天(即星期三)晚上的差异备份
最后依次恢复当天(即星期四)上午9:00、10:00、11:00的日志备份

结论:要根据不同的还原需求选择对应的还原策略

还原数据库时失败怎么办?

请添加图片描述
以上失败原因:没有断开目标数据库“bookDB4”的连接,而要断开该数据库的连接需要查询得到该数据库的连接的 spid 并使用命令通过 spid 来断开该数据库的连接;
有一个最简单方便的方法可以马上断开该数据库的连接:右键目标数据库,进入“属性”,在“选项”中找到“状态”,将“限制访问”改为“SINGLE_USER”,点击确定,点击“是”以此关闭该数据库的连接
完成以上操作后,再次还原数据库备份,结果成功

练习

--(1)在“图书类型”数据表中添加记录数据
select * from 图书类型
insert into 图书类型 values('aa','名称测试',null)

--(2)执行用户数据库book的差异备份操作
--右键目标数据库,进入“属性”,在“选项”中可选择对该数据库的恢复模式
--图形操作,如下:
--服务器中:服务器对象-备份设备(右键选择“新建备份设备”)
--在“常规”中,填入设备名称,“文件”框中选择将备份存放的路径同时要给备份文件起名:文件名.bak,点击确定
--右键目标数据库,选择“任务”-“备份”,在“常规”中选择备份类型,在下方目标框框中删除原有的默认备份路径,
--点击“添加”,选择刚才新建的备份设备,点击确定,完成备份

--(3)修改“图书类型”数据表中的数据
update 图书类型 set 描述信息 = '描述测试' where 图书类型代号 = 'aa' 
delete FROM 图书类型  where 图书类型代号 = 'aa' 

--(4)执行用户数据库book的事务日志备份操作
--与(2)相似

--(5)查看用户数据库book的差异备份和事务日志备份
--服务器中:服务器对象-备份设备(双击打开此备份设备),发现左侧新增“介质内容”一栏,该栏中的“备份集”出现了刚刚备份的备份文件

--(6)恢复备份
--右键目标数据库,选择“任务”-“还原”-“数据库”,设置好“选项”中的“还原选项”,点击确定,完成备份的还原
  • 4
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值