SQL语言学习

目录

一、创建数据库

1、详细写法

2、简略写法

二、创建数据表

三、表结构和约束的维护

1、添加列

2、删除列

3、修改列

4、维护约束(删除、添加)

 四、数据的插入、修改、删除

(1)插入数据

1、标准写法

2、简写

3、一次性插入多行数据

(2)数据的修改

(3)数据的删除

五、数据查询

SQL中常用的运算符

1、基础查询

2、条件查询

3、模糊查询

4、分组查询

5、多表查询 

 六、聚合函数

1、常用的聚合函数

 2、示例



一、创建数据库

1、详细写法

--创建数据库
create database DBTEST
on   --数据文件
(
	name = 'DBTEST', --逻辑名称
	filename = 'E:\Data\DBTEST.mdf', -- 物理路径和名称
    size = 5MB,  --文件的初始大小
	filegrowth = 2MB --文件增长方式可以写大小也可以写百分比 
)
log on  --日志文件
(
	name = 'DBTEST_log', --逻辑名称
	filename = 'E:\Data\DBTEST.ldf', -- 物理路径和名称
    size = 5MB,  --文件的初始大小
	filegrowth = 2MB --文件增长方式可以写大小也可以写百分比 
)

删除数据库

drop database DBTEST  --删除数据库

建立数据库前,可以先判定数据库中有没有该名称的数据库,如果有就删除,没有就创建

此处理方式最好只在学习阶段使用,在正式生产环境中慎用,操作不当可能会删除重要数据

  

if exists(select * from sys.databases where name = 'DBTEST')
	drop database DBTEST
--创建数据库
create database DBTEST
on   --数据文件
(
	name = 'DBTEST', --逻辑名称
	filename = 'E:\Data\DBTEST.mdf', -- 物理路径和名称
    size = 5MB,  --文件的初始大小
	filegrowth = 2MB --文件增长方式可以写大小也可以写百分比 
)
log on  --日志文件
(
	name = 'DBTEST_log', --逻辑名称
	filename = 'E:\Data\DBTEST.ldf', -- 物理路径和名称
    size = 5MB,  --文件的初始大小
	filegrowth = 2MB --文件增长方式可以写大小也可以写百分比 
)

与手动创建效果相同

2、简略写法

--创建数据库简写
create database DBTEST1

如果按照上述方式创建数据库,数据库的数据文件和日志文件的相关信息,全部采取默认值

二、创建数据表

建表操作在数据库中执行

建表前,如果该表已经存在,则能在数据库视图中查看到该表

name:表名称

type:表类型   U---用户自定义

--切换数据库
use DBTEST

--创建表基本语法
--create table 表名
--(
--	字段名1 数据类型
--	字段名2 数据类型
--)
--判断表是否存在
if exists(select * from sys.objects where name = 'Department' and type = 'U')
	drop table Department
--建表(职位、职级、员工)
create table Department
(
	--部门编号    primary key:主键,唯一标识表中的每一行记录
	--            identity(1,1):自动增长,初始值1,增长步长1
	DepartmentID int primary key identity(1,1),
	--部门名称
	DepartmentName nvarchar(50) not null,
	--部门描述
	DepartmentRemark text
)
--职级
create table [Rank]
(
	--职级编号    primary key:主键,唯一标识表中的每一行记录
	--            identity(1,1):自动增长,初始值1,增长步长1
	RankID int primary key identity(1,1),
	--职级名称
	RankName nvarchar(50) not null,
	--职级描述
	RankRemark text

)
--员工
create table People
(
	PeopleId int primary key identity(1,1),   --员工编号
	DepartmentID int references Department(DepartmentID) not null,--部门(引用外键)
	RankID int references [Rank](RankID) not null,--职级(引用外键)
	PeopleName nvarchar(50) not null,   --姓名
	PeopleSex nvarchar(1) default('男') check(PeopleSex='男' or PeopleSex='女') not null, --性别
	PeopleBirth datetime not null, --出生日期
	PeopleSalary decimal(12,2) check(PeopleSalary>=1000 and PeopleSalary<=1000000), --月薪
	PeoplePhone varchar(20) unique not null,  --电话号码
	PeopleAddress nvarchar(50),  --地址
	PeopleAddTime smalldatetime default(getdate()) --添加时间

)

 外键:引用其他表的主键。如果将其他表的主键作为该表的字段,则在存储该字段数据时会检测数据是否符合主键所在的表

SQL语言中的字符串类型

--C#中字符串为string,但是SQL中没有string这种数据类型
--SQL中的字符串如下:
--char:定长,char(10),无论存储数据是否真的到了10个字节,都要占用10个字节
--char(10)存储'ab',仍然占用10个字节
--varchar:变长,varchar(10),最多占用10个字节
--varchar(10)存储'ab',占用2个字节
--text:长文本
--char,varchar,text前面加n:存储unicode字符,对中文友好
--varchar(50):存储100个字母或者50个汉字
--nvarchar(50):存储100个字母或者100个汉字

三、表结构和约束的维护

注:下述操作在实际业务中尽量减少使用,一般会考虑周全,做好充足预留

1、添加列

--添加列
--alter table 表名 add 新列名 数据类型
--给员工添加一列邮箱
alter table People add PeopleMail varchar(200)

2、删除列

--删除列
--alter table 表名 drop column 列名 
--删除邮箱这一列
alter table People drop column PeopleMail 

3、修改列

--修改列
--alter table 表名 alter column 列名 数据类型
--修改地址varchar(300)为varchar(200)
alter table People alter column PeopleAddress varchar(200)
--当该列没有数据时执行成功,如果该列已有数据,数据长度大于修改后或者数据类型不符合则会报错

4、维护约束(删除、添加)

----维护约束(删除、添加)
--删除约束
alter table 表名 drop constraint 约束名
--删除月薪的约束
alter table People drop constraint CK__People__PeopleSe__48CFD27E
--添加约束(check约束)
alter table 表名 add constraint 约束名 check(表达式)
--添加约束(主键)
alter table 表名 add constraint 约束名 primary key(列名)
--添加约束(唯一)
alter table 表名 add constraint 约束名 unique(列名)
--添加约束(默认值)
alter table 表名 add constraint 约束名 default 默认值 for 列名
--添加约束(外键)
alter table 表名 add constraint 约束名 foreign key 列名 references 关联表名(列名(主键))

 四、数据的插入、修改、删除

(1)插入数据

1、标准写法
--向部门表插入数据
insert into Department(DepartmentName,DepartmentRemark)
values('市场部','.....')
insert into Department(DepartmentName,DepartmentRemark)
values('软件部','.....')
insert into Department(DepartmentName,DepartmentRemark)
values('企划部','.....')
2、简写
--简写:不建议使用,当调整表的结构时会插入错误数据
insert into Department values('硬件部','.....')
3、一次性插入多行数据
--一次性插入多行数据
insert into Department(DepartmentName,DepartmentRemark)
select '测试部','......' union
select '实施部','......' union
select '产品部','......' 

示例:

------------向职级表中插入数据
insert into [Rank](RankName,RankRemark)
values('初级','.....')
insert into [Rank](RankName,RankRemark)
values('中级','.....')
insert into [Rank](RankName,RankRemark)
values('高级','.....')
------------向员工表插入数据
insert into People([DepartmentID],[RankID],[PeopleName],[PeopleSex],[PeopleBirth],[PeopleSalary],[PeoplePhone],
[PeopleAddress])
values(10,1,'刘备','男','1988-8-8',5000,13888888888,'北京')

(2)数据的修改

--修改数据
update 表名 set 字段1=值1,字段2=值2 where 条件

(3)数据的删除

---删除数据
--方式1
delete from 表名 where 条件
delete from Department  --删除表中所有数据,表对象结构依然存在
delete from [Rank]
delete from People
--方式2
drop table People  --删除表对象
--方式3
truncate table People --清空表数据,表对象结构依然存在

truncate与delete区别:

1、truncate清空所有数据后面不能带条件,delete可以删除所有数据也可以带条件,删除符合条件的数据

2、自动编号

假设表中的自动编号为1、2、3、4、5

使用truncate清空数据后,编号仍然是1、2、3、4、5

使用delete删除数据,删除的自动编号将永远不存在了

即:如果使用了delete删除了所有数据之后再添加数据,编号变成了6、7、8、9、10

五、数据查询

SQL中常用的运算符

=:等于,比较是否相等及赋值

!=:比较不等于

>:比较大于

<:比较小于

>=:比较大于等于

<=:比较小于等于

IS NULL:比较为空

IS NOT NULL:比较不为空

in:比较是否在其中

like:模糊查询

Between.....and..... :比较是否在两者之间

and:逻辑与

or:逻辑或

not:逻辑非(条件成立,表达式则不成立;条件不成立,表达式则成立)

1、基础查询

--查询所有列所有行
select * from People --*代表所有列
select * from [Rank]
select * from Department
--查询指定列(姓名、性别、生日、月薪、电话)
select PeopleName,PeopleSex,PeopleBirth,PeopleSalary,PeoplePhone from People
--查询指定列(姓名、性别、生日、月薪、电话)显示中文列名
select PeopleName 姓名,PeopleSex 性别,PeopleBirth 生日,PeopleSalary 月薪,PeoplePhone 电话 from People
--查询出员工所在的城市(不需要重复数据显示)
select distinct(PeopleAddress) from People
--假设准备加工资(上调20%),查询出加工资前和加工资后的数据对比的员工数据
select PeopleName,PeopleSex,PeopleSalary 加薪前工资,PeopleSalary*1.2 加薪后工资 from People

2、条件查询

--查询性别为女的员工
select * from People where PeopleSex='女'
--查询工资大于等于10000元的员工信息
select * from People where PeopleSalary>=10000
--查询性别为女,工资大于等于10000元的员工信息(多条件)
select * from People where PeopleSex='女' and PeopleSalary >=10000
--查询月薪大于等于10000的员工,或者月薪大于等于8000的女员工
select * from People where PeopleSalary>=10000 or (PeopleSalary>=8000 and PeopleSex = '女')
--查询出生年月在1980-1-1之后,而且月薪大于10000的女员工
select * from People where PeopleBirth>=1980-1-1 and PeopleSalary >10000 and PeopleSex = '女'
--查询月薪在10000到20000之间的员工信息
--方式1
select * from People where PeopleSalary>=10000 and PeopleSalary <=20000
--方式2
select * from People where PeopleSalary between 10000 and 20000
--查询出地址在武汉或者北京的员工信息
--方式1
select * from People where PeopleAddress = '武汉' or PeopleAddress = '北京'
--方式2
select * from People where PeopleAddress in('武汉','北京')


--排序
--查询所有员工信息,根据工资排序,降序
--asc(ascend):升序,默认升序  desc(descend):降序
select * from People order by PeopleSalary desc
--查询所有员工信息,根据姓名长度排序(降序)
select * from People order by len(PeopleName) desc
--查询出工资最高的5个人信息
select top 5 * from People order by PeopleSalary desc
--查询出工资最高的10%的员工信息
select top 10 percent * from People order by PeopleSalary desc

--null:空值
--查询出地址没有填写的员工信息
select * from People where PeopleAddress is null
--查询出地址已经填写的员工信息
select * from People where PeopleAddress is not null

--查询80后的员工信息
select * from People where PeopleBirth>='1980-1-1' and PeopleBirth <'1990-1-1'
select * from People where PeopleBirth  between '1980-1-1' and '1989-12-31'
select * from People where year(PeopleBirth)  between '1980' and '1989'

--查询30-40岁,月薪在15000到30000之间的员工
select * from People where (year(GETDATE())-year(PeopleBirth))>=30 and (year(GETDATE())-year(PeopleBirth))<=40
and PeopleSalary>=15000 and PeopleSalary<=30000
select * from People where (year(GETDATE())-year(PeopleBirth)) between 30 and 50
and PeopleSalary between 15000 and 30000

--查询工资比王昭君高的员工信息
select * from People where PeopleSalary>
(select PeopleSalary from People where PeopleName='王昭君')
--查询出和刘备在一个城市的员工信息
select * from People where PeopleAddress = 
(select PeopleAddress from People where PeopleName = '刘备')
--查询出星座是巨蟹座的员工信息(6.22-7.22)
select * from People where 
(MONTH(PeopleBirth)=6 and DAY(PeopleBirth)>=22) or (MONTH(PeopleBirth)=7 and DAY(PeopleBirth)<=22)
--查询出生肖是鼠的员工信息
--1998 虎   1998%12=6
-- 鼠 、牛、虎、兔、龙、蛇、马、羊、猴、鸡、狗、猪
-- 4    5    6   7   8   9   10  11  0   1   2   3
select * from People where year(PeopleBirth) % 12 = 4
--查询所有员工信息,添加一列,显示生肖
select *,
case
   when year(PeopleBirth)%12=4 then '鼠'
   when year(PeopleBirth)%12=5 then '牛'
   when year(PeopleBirth)%12=6 then '虎'
   when year(PeopleBirth)%12=7 then '兔'
   when year(PeopleBirth)%12=8 then '龙'
   when year(PeopleBirth)%12=9 then '蛇'
   when year(PeopleBirth)%12=10 then '马'
   when year(PeopleBirth)%12=11 then '羊'
   when year(PeopleBirth)%12=0 then '猴'
   when year(PeopleBirth)%12=1 then '鸡'
   when year(PeopleBirth)%12=2 then '狗'
   when year(PeopleBirth)%12=3 then '猪'
   else ''
end
生肖 from People
--when之后的判定依据一致,可简化代码
select *,
case year(PeopleBirth)%12
   when 4 then '鼠'
   when 5 then '牛'
   when 6 then '虎'
   when 7 then '兔'
   when 8 then '龙'
   when 9 then '蛇'
   when 10 then '马'
   when 11 then '羊'
   when 0 then '猴'
   when 1 then '鸡'
   when 2 then '狗'
   when 3 then '猪'
   else ''
end 生肖 
from People

3、模糊查询

模糊查询使用like关键字和通配符结合来实现,通配符具体含义如下:

%:代表匹配0个字符,1个字符或多个字符

_:代表匹配有且只有一个字符

[]:代表匹配范围内

[^]:代表匹配不在范围内

--查询姓刘的员工信息
select * from People where PeopleName like '刘%'
--查询名字中含有“尚”的员工信息
select * from People where PeopleName like '%尚%'
--查询姓刘的员工,名字是两个字
select * from People where PeopleName like '刘_'
select * from People where SUBSTRING(PeopleName,1,1)  = '刘' and len(PeopleName) = 2
--查询出电话号码是138开头的员工信息
select * from People where PeoplePhone like '138%'
--查询出电话号码是138开头的,第四位好像是7或者8,最后一个号码是5
select * from People where PeoplePhone like '138[7,8]%5'
--查询出电话号码是138开头的,第四位好像是2-5之间,最后一个号码不是2和3
select * from People where PeoplePhone like '138[2,3,4,5]%[^2,3]'
select * from People where PeoplePhone like '138[2-5]%[^2-3]'

  4、分组查询

--分组查询
--(1)根据员工所在地区分组统计员工人数,员工工资总和,平均工资,最高工资和最低工资
--方案1:使用union实现   缺点:union使用场景有限制,必须列数一致   代码量大
select COUNT(*) 人数,MAX(PeopleSalary) 最高工资,MIN(PeopleSalary) 最低工资,
SUM(PeopleSalary) 工资总和,AVG(PeopleSalary) 平均工资 from People 
where PeopleAddress='北京'
union
select COUNT(*) 人数,MAX(PeopleSalary) 最高工资,MIN(PeopleSalary) 最低工资,
SUM(PeopleSalary) 工资总和,AVG(PeopleSalary) 平均工资 from People 
where PeopleAddress='武汉'
--方案2:group by分组
select PeopleAddress 地区, COUNT(*) 人数,MAX(PeopleSalary) 最高工资,MIN(PeopleSalary) 最低工资,
SUM(PeopleSalary) 工资总和,AVG(PeopleSalary) 平均工资 from People 
group by PeopleAddress
--(2)根据员工所在地区分组统计员工人数,员工工资总和,平均工资,最高工资和最低工资
--注意:1985年及以后出生的员工不参与统计
select PeopleAddress 地区, COUNT(*) 人数,MAX(PeopleSalary) 最高工资,MIN(PeopleSalary) 最低工资,
SUM(PeopleSalary) 工资总和,AVG(PeopleSalary) 平均工资 
from People 
where PeopleBirth<'1985-1-1'
group by PeopleAddress
--(3)根据员工所在地区分组统计员工人数,员工工资总和,平均工资,最高工资和最低工资
--注意:要求筛选出员工人数至少在2人及以上的记录,并且1985年及以后出生的员工不参与统计
select PeopleAddress 地区, COUNT(*) 人数,MAX(PeopleSalary) 最高工资,MIN(PeopleSalary) 最低工资,
SUM(PeopleSalary) 工资总和,AVG(PeopleSalary) 平均工资 
from People 
where PeopleBirth<'1985-1-1'
group by PeopleAddress
having COUNT(*)>=2
--普通条件放在group by前面,含有聚合函数的条件放在group by后面,因为先分好组才能计算组内的数据 

5、多表查询 

--多表查询
--笛卡尔乘积
select * from People,Department
--查询结果是将People所有记录与Department所有记录依次排列组合形成新的结果
--People中16条数据  Department中6条数据  则该查询结果为16*6 = 96条记录


--简单多表查询
--(1)查询员工信息,显示部门名称
select * from People,Department where People.DepartmentID = Department.DepartmentID
--(2)查询员工信息,显示职级名称
select * from People,[Rank] where People.RankID = [Rank].RankID
--(2)查询员工信息,显示部门名称,显示职级名称
select * from People,Department,[Rank] 
where People.DepartmentID = Department.DepartmentID and People.RankID = [Rank].RankID

--内连接查询
--(1)查询员工信息,显示部门名称
select * from People inner join Department on People.DepartmentID = Department.DepartmentID
--(2)查询员工信息,显示职级名称
select * from People inner join [Rank] on People.RankID = [Rank].RankID
--(2)查询员工信息,显示部门名称,显示职级名称
select * from People 
inner join Department on People.DepartmentID = Department.DepartmentID
inner join [Rank] on People.RankID = [Rank].RankID

--简单多表查询与内连接共同的特点:不符合主外键关系的数据不会被显示出来

--外连接(左外连接,右外连接,全外连接)
--左外连:以左表为主表进行数据显示,主外键关系找不到的数据null取代   A left join B = B right join A
--(1)查询员工信息,显示部门名称
select * from People left join Department on People.DepartmentID = Department.DepartmentID
--右外连:以右表为主表进行数据显示,主外键关系找不到的数据null取代
--(1)查询员工信息,显示部门名称
select * from People right join Department on People.DepartmentID = Department.DepartmentID
--全外连:两张表的数据,无论是否符合关系,都要显示
--(1)查询员工信息,显示部门名称
select * from People full join Department on People.DepartmentID = Department.DepartmentID


--自连接(自己连接自己)
--同一个表中存在父子关系情况下可以使用
create table Dept
(
	DeptId int primary key, --部门编号
	DeptName varchar(50),   --部门名称
	ParentId int        --上级部门名称
)
truncate table Dept
--一级
insert into Dept(DeptId,DeptName,ParentId)values (1,'软件部',0)
insert into Dept(DeptId,DeptName,ParentId)values (2,'硬件部',0)
--二级
insert into Dept(DeptId,DeptName,ParentId)values (3,'软件研发部',1)
insert into Dept(DeptId,DeptName,ParentId)values (4,'软件测试部',1)
insert into Dept(DeptId,DeptName,ParentId)values (5,'软件实施部',1)
insert into Dept(DeptId,DeptName,ParentId)values (6,'硬件研发部',2)
insert into Dept(DeptId,DeptName,ParentId)values (7,'硬件测试部',2)
insert into Dept(DeptId,DeptName,ParentId)values (8,'硬件实施部',2)

select * from Dept
--部门编号   部门名称   上级名称 
--3          软件研发部  软件部

--.............................
select A.DeptId 部门编号,A.DeptName 部门名称,B.DeptName from Dept A
inner join Dept B on A.ParentId = B.DeptId

 注:

简单多表查询与内连接共同特点:不符合主外键关系的数据不会被显示出来

外连接与内连接的区别:

内连接:不符合主外键关系的数据不会显示出来

外连接:根据外连接的类型不同

(1)左外连:以左表为主进行数据显示,主外键关系不符合的数据null取代

(2)右外连:以右表为主进行数据显示,主外键关系不符合的数据null取代

(3)全外连:两张表的数据,无论是否符合关系,都要显示

 六、聚合函数

1、常用的聚合函数

sqlserver中聚合函数主要有:

count:求数量

max:求最大值

min:求最小值

sum:求和

avg:求平均值

 2、示例

--聚合函数
--(1)求员工总人数
select COUNT(*) 人数 from People
--(2)求最大值,求最高工资
select MAX(PeopleSalary) 最高工资 from People
--(3)求最小值,求最少工资
select MIN(PeopleSalary) 最低工资 from People
--(4)求和,求所有员工工资总和
select SUM(PeopleSalary) 工资总和 from People
--(5)求平均值,求所有员工的平均工资
select AVG(PeopleSalary) 平均工资 from People
select ROUND(AVG(PeopleSalary),2)  平均工资 from People
--(6)求数量、最大值、最小值、总和、平均值在一行显示
select COUNT(*) 人数,MAX(PeopleSalary) 最高工资,MIN(PeopleSalary) 最低工资,
SUM(PeopleSalary) 工资总和,AVG(PeopleSalary) 平均工资 from People
--(7)查询出北京地区的员工人数,总工资,最高工资,最低工资和平均工资
select COUNT(*) 人数,MAX(PeopleSalary) 最高工资,MIN(PeopleSalary) 最低工资,
SUM(PeopleSalary) 工资总和,AVG(PeopleSalary) 平均工资 from People 
where PeopleAddress='北京'
--(8)求出工资比平均高的人员信息
select * from People where PeopleSalary>
(select ROUND(AVG(PeopleSalary),2)  平均工资 from People)
--(9)求数量,年龄最大值,年龄最小值,年龄总和,年龄平均值,在一行显示
--方案1
select COUNT(*) 人数,
MAX(YEAR(GETDATE())-YEAR(PeopleBirth)) 年龄最大值,
MIN(YEAR(GETDATE())-YEAR(PeopleBirth)) 年龄最小值,
SUM(YEAR(GETDATE())-YEAR(PeopleBirth)) 年龄总和,
AVG(YEAR(GETDATE())-YEAR(PeopleBirth)) 年龄平均值 
from People
--方案2
select DATEDIFF(YEAR,PeopleBirth,GETDATE()) from People
select COUNT(*) 人数,
MAX(DATEDIFF(YEAR,PeopleBirth,GETDATE())) 年龄最大值,
MIN(DATEDIFF(YEAR,PeopleBirth,GETDATE())) 年龄最小值,
SUM(DATEDIFF(YEAR,PeopleBirth,GETDATE())) 年龄总和,
AVG(DATEDIFF(YEAR,PeopleBirth,GETDATE())) 年龄平均值 
from People
--(10)计算出月薪在10000以上的男性员工的最大年龄,最小年龄和平均年龄
select '月薪大于10000' 月薪,'男' 性别,
MAX(DATEDIFF(YEAR,PeopleBirth,GETDATE())) 年龄最大值,
MIN(DATEDIFF(YEAR,PeopleBirth,GETDATE())) 年龄最小值,
AVG(DATEDIFF(YEAR,PeopleBirth,GETDATE())) 年龄平均值 
from People where PeopleSalary>10000 and PeopleSex='男'
--(11)统计出所有女员工数量以及最大年龄最小年龄和平均年龄
select COUNT(*) 数量,
MAX(DATEDIFF(YEAR,PeopleBirth,GETDATE())) 年龄最大值,
MIN(DATEDIFF(YEAR,PeopleBirth,GETDATE())) 年龄最小值,
AVG(DATEDIFF(YEAR,PeopleBirth,GETDATE())) 年龄平均值 
from People where PeopleSex='女'
--(2)求出年龄比平均年龄高的人员信息
select * from People where DATEDIFF(YEAR,PeopleBirth,GETDATE())>
(select AVG(YEAR(GETDATE())-YEAR(PeopleBirth)) from People 平均年龄)

七、数据库设计

1、数据库结构设计三范式

第一范式是对属性的原子性,要求属性具有原子性,不可再分解

如有如下表结构设计:

create table Student
(
	StuId varchar(20) primary key,--学号
	StuName varchar(20) not null,--学生姓名
	StuContact varchar(50) not null--联系方式
)
insert into Student(StuId,StuName,StuContact)
values('001','刘备','QQ:2319440854;Tel:15779160135')

 如果我有对电话查询的要求,则会加大查询难度

上述设计不符合第一范式,联系方式这一列并不是不可再分的最小单元,应修改为如下结构

create table Student
(
	StuId varchar(20) primary key,--学号
	StuName varchar(20) not null,--学生姓名
	Tel  varchar(20) not null,--电话
	QQ  varchar(20) not null--QQ
)
insert into Student(StuId,StuName,Tel,QQ)
values('001','刘备','15779160135','QQ:2319440854')

第二范式:对表数据的唯一性,要求表数据要有唯一标识,即实体的唯一性,即不存在部分依赖

如有如下表结构设计

--学生选课表
create table StudentCourse
(
	StuId varchar(20),--学号
	StuName varchar(20) not null,--学生姓名
	CourseId varchar(20),--课程编号
	CourseName varchar(20),--课程名称
	CourseScore int not null--分数
)
insert into StudentCourse(StuId,StuName,CourseId, CourseName,CourseScore)
values('001','刘备','001','语文',80)
insert into StudentCourse(StuId,StuName,CourseId, CourseName,CourseScore)
values('001','刘备','002','数学',70)
insert into StudentCourse(StuId,StuName,CourseId, CourseName,CourseScore)
values('002','关羽','003','英语',80)
insert into StudentCourse(StuId,StuName,CourseId, CourseName,CourseScore)
values('003','张飞','003','英语',90)

表中学生这个实体,在记录中存在多条,不能保证唯一性,存在冗余,课程同理

造成结果:

(1)数据的冗余

(2)维护困难:比如添加一名学生但该学生还未开始选课;比如语文只有刘备选了,刘备退学后删除时则把课程也删除了;加入英语被1000个人选课,如果要修改课程名称则相对繁琐

 上述设计中有两个事物,一个是学生信息,一个是课程信息,很显然这两个事物都没有保证实体的唯一性,这里的姓名依赖学号,课程名称依赖课程编号,所有不符合第二范式。

修改为如下结构:

--课程表
create table Course
(
	CourseId int primary key identity(1,1),
	CourseName varchar(20) not null,
	CourseContent text --课程介绍
)	
insert into Course(CourseName,CourseContent)values('HTML','静态网页的制作')
insert into Course(CourseName,CourseContent)values('WinForm','Windows应用程序开发')
--学生表
create table Student
(
	StuId int primary key identity(1,1) ,--学号
	StuName varchar(20) not null,--学生姓名
	Sex  char(2) not null,--学生性别
)
insert into Student(StuName,Sex)values('刘备','男')
insert into Student(StuName,Sex)values('关羽','男')

--考试信息表
create table Exam
(
	ExamId int primary key identity(1,1),--选课成绩编号
	StuId int not null,--学生编号
	CourseId int not null,--课程编号
	Score int not null--考试分数
)
insert into Exam(StuId,CourseId,Score) values(1,1,90)
insert into Exam(StuId,CourseId,Score) values(1,2,80)
insert into Exam(StuId,CourseId,Score) values(2,2,85)

第三范式:要求任何字段不能由其他字段派生出来,要求字段没有冗余即不存在传递依赖

如有如下表结构设计:

create table Student
(
	StuId varchar(20) primary key,--学号
	StuIdName varchar(20) not null,--学生姓名
	ProfessionalId int not null,--专业编号
	ProfessionalName varchar(50),--专业名称
    ProfessionalRemark varchar(200)--专业介绍
)
insert into Student(StuId,StuIdName,ProfessionalId,ProfessionalName,ProfessionalRemark)
values('001','刘备',1,'计算机','最牛的专业')
insert into Student(StuId,StuIdName,ProfessionalId,ProfessionalName,ProfessionalRemark)
values('002','关羽',2,'工商管理','管理学的基础专业')
insert into Student(StuId,StuIdName,ProfessionalId,ProfessionalName,ProfessionalRemark)
values('003','张飞',1,'计算机','最牛的专业')

上述设计中专业名称字段和专业介绍字段,在数据库中会产生很多冗余数据,不满足第二范式,优化方案如下:

create table Professional
(
	ProfessionalId int primary key identity(1,1),--专业编号
	ProfessionalName varchar(50),--专业名称
	ProfessionalRemark varchar(200) --专业介绍
)
create table Stduent
(
	StuId varchar(20) primary key,
	StuName varchar(20) not null,
	ProfessionalId int not null
)
insert into Professional(ProfessionalName,ProfessionalRemark)values('计算机','最牛的专业')
insert into Professional(ProfessionalName,ProfessionalRemark)values('工商管理','管理学的基础专业')
insert into Stduent(StuId,StuName,ProfessionalId)values('001','刘备',1)
insert into Stduent(StuId,StuName,ProfessionalId)values('002','关羽',2)
insert into Stduent(StuId,StuName,ProfessionalId)values('003','张飞',1)

2、表关系

(1)一对一

(2)一对多(多对一)

(3)多对多

八、数据库的高级应用

在学习数据库的高级应用之前,先建立一个示例数据库

--业务需求说明--------------------------------------
--模拟银行业务,设计简易版的银行数据库表结构,要求可以完成以下基本功能需求
--1、银行开户(注册个人信息)及开卡(办理银行卡)(一个人可以办理多张银行卡,但是最多只能办理3张)
--2、存钱
--3、查询余额
--4、取钱
--5、转账
--6、查看交易记录
--7、账户挂失
--8、账户注销

--表设计----------------------------------
--1、账户信息表
--2、银行卡表
--3、交易信息表(存钱和取钱的记录)
--4、转账信息表
--5、状态信息变化表(银行卡状态1:正常,2:挂失,3:冻结,4:注销  )
--表结构设计
create table AccountInfo--账户信息表
(
	AccountId int primary key identity(1,1),--账户编号
	AccountCode varchar(20) not null,--身份证号码
	AccountPone varchar(20) not null,--电话号码
	RealName varchar(20) not null,--真实姓名
	OpenTime smalldatetime not null--开户时间
)
create table BankCard--银行卡
(
	CardNo varchar(30) primary key,--银行卡卡号
	AccountId int references AccountInfo(AccountId) not null,--账户编号(与账户信息形成主外键关系)
	CardPwd varchar(30) not null,--银行卡密码
	CardMoney money not null,--银行卡余额
	CardState int not null,--1:正常 2:挂失 3:冻结 4:注销
	CardTime smalldatetime default(getdate())
)
create table CardExchange--交易信息表(存钱和取钱的记录)
(
	ExchangeId int primary key identity(1,1),--交易自动编号
	CardNo varchar(30) references BankCard(CardNo),--银行卡号(与银行卡表形成主外键关系)
	MoneyInBank money not null,--存钱金额
	MoneyOutBank money not null,--取钱金额
	ExchangeTime smalldatetime not null--交易时间
) 
create table CardTransfer--转账信息表
(
	TransferId int primary key identity(1,1),--转账自动编号
	CardNoOut varchar(30) not null,--转出银行卡号(与银行卡表形成主外键关系)
	CardNoIn varchar(30) not null,--转入银行卡号(与银行卡表形成主外键关系)
	TransferMoney money not null,--交易金额
	TransferTime smalldatetime not null--交易时间
)
create table CardStateChange--状态信息变化表(存储银行卡状态1:正常 2:挂失 3:冻结 4:注销)
(
	StateId int primary key identity(1,1),--状态信息自动编号
	CardNo varchar(30) references BankCard(CardNo) not null,--银行卡号(与银行卡表形成主外键关系 )
	OldState int not null,--银行卡原始状态
	NewState int not null,--银行卡新状态
	StateWhy varchar(200) not null,--状态变化原因
	StateTime smalldatetime default(getdate()),--记录产生时间 
)

--为刘备、关羽、张飞三个人进行开户开卡的操作
--刘备身份证:123456789   银行卡号:423556566576754
--关羽身份证:145787687   银行卡号:876545365656657
--张飞身份证:415656667   银行卡号:255676776785643
insert into AccountInfo(AccountCode,AccountPone,RealName,OpenTime)
values('123456789','15779160135','刘备',GETDATE())
insert into BankCard(CardNo,AccountId,CardPwd,CardMoney,CardState,CardTime)
values('423556566576754','1','123456',0,1,GETDATE())
insert into AccountInfo(AccountCode,AccountPone,RealName,OpenTime)
values('145787687','15352166545','关羽',GETDATE())
insert into BankCard(CardNo,AccountId,CardPwd,CardMoney,CardState,CardTime)
values('876545365656657','2','123456',0,1,GETDATE())
insert into AccountInfo(AccountCode,AccountPone,RealName,OpenTime)
values('415656667','15637877635','张飞',GETDATE())
insert into BankCard(CardNo,AccountId,CardPwd,CardMoney,CardState,CardTime)
values('255676776785643','3','123456',0,1,GETDATE())

--进行存钱操作,刘备存钱2000元,关羽存钱8000元,张飞存钱500000元
update BankCard set CardMoney=CardMoney+2000 where CardNo = '423556566576754'
insert into CardExchange(CardNo,MoneyInBank,MoneyOutBank,ExchangeTime)
values('423556566576754',2000,0,GETDATE())
update BankCard set CardMoney=CardMoney+8000 where CardNo = '876545365656657'
insert into CardExchange(CardNo,MoneyInBank,MoneyOutBank,ExchangeTime)
values('876545365656657',8000,0,GETDATE())
update BankCard set CardMoney=CardMoney+500000 where CardNo = '255676776785643'
insert into CardExchange(CardNo,MoneyInBank,MoneyOutBank,ExchangeTime)
values('255676776785643',500000,0,GETDATE())

--转账:刘备给张飞转账1000元
update BankCard set CardMoney=CardMoney+1000 where CardNo = '255676776785643'
update BankCard set CardMoney=CardMoney-1000 where CardNo = '423556566576754'
insert into CardTransfer(CardNoIn,CardNoOut,TransferMoney,TransferTime) 
values('255676776785643','423556566576754',1000,GETDATE())

建立的数据库;

1、信息打印

--信息打印
print 'hello,sql'
select 'hello,sql'

2、变量

(1)局部变量

局部变量以@开头,先声明,再赋值 

--局部变量
--声明
declare @str varchar(20)
--赋值方式1
set @str = 'I like Sql'
--赋值方式2
select @str = 'I like Sql'
print @str
--set和select进行赋值时的区别
--set:赋值变量指定的值
--select:一般用于表中查询出的数值赋值给变量,如果查询结果有多条,取最好一条赋值
--exp:select @a = 字段名 from 表名 
--当前表最后一行的某个字段值给@a

(2)全局变量

全局变量以@@开头,由系统定义和维护

@@ERROR:返回执行的上一个语句的错误号

@@IDENTITY:返回最后插入的标识值

@@MAX_CONNECTIONS:返回允许同时进行的最大用户连接数

@@ROWCOUNT:返回受上一语句影响的行数

@@SERVERNAME:返回运行SQL Server的本地服务器的名称

@@SERVICENAME:返回SQL Server正在其下运行的注册表项的名称

@@TRANCOUNT:返回当前连接的活动事务数

@@LOCK_TIMEOUT:返回当前会话的当前锁定超时设置(毫秒)

 示例:

--为赵云此人进行开户开卡操作,赵云身份证:423543253
insert into AccountInfo(AccountCode,AccountPone,RealName,OpenTime)
values('423543253','15777881135','赵云',GETDATE())
declare @AccountId int
set @AccountId = @@IDENTITY
insert into BankCard(CardNo,AccountId,CardPwd,CardMoney,CardState,CardTime)
values('4235879656576754',@AccountId,'123456',0,1,GETDATE())
select * from AccountInfo

--求出张飞的银行卡卡号和余额,张飞身份证:415656667
--方案1
select CardNo 卡号,CardMoney 余额 from AccountInfo 
inner join BankCard on AccountInfo.AccountId = BankCard.AccountId 
where AccountCode = '415656667'
--方案2
declare @AccountId int
select @AccountId = (select AccountId from AccountInfo where AccountCode = '415656667')
select CardNo 卡号,CardMoney 余额 from BankCard where AccountId = @AccountId

 (3)go语句

go语句作用1:等待go语句之前代码执行完成之后才能执行后面的代码

go语句作用2:改变局部变量的作用范围

--go语句
--(1)等待go语句之前代码执行完成之后才能执行后面的代码
create database Test
go  --如果没有go语句 
use Test  --则在use Test时会报错,因为数据库还未创建成功,无法切换
create table AccountInfo--账户信息表
(
	AccountId int primary key identity(1,1),--账户编号
	AccountCode varchar(20) not null,--身份证号码
	AccountPone varchar(20) not null,--电话号码
	RealName varchar(20) not null,--真实姓名
	OpenTime smalldatetime not null--开户时间
)

--(2)批处理结束的一个标志
declare @num int--@num在这三句代码中作用范围是全局
set @num=100
set @num =100

declare @num1 int--@num在这代码中作用范围是go之前
set @num1=100
go
set @num1 =100

go
declare @num1 int--@num在这代码中作用范围是两个go之间
set @num1=100
go
set @num1 =100

3、运算符

SQL中使用的运算符分为7种

算数运算符:加(+)、减(-)、乘(*)、除(/)、模(%)

逻辑运算符:AND、OR、LIKE、BETWEEN、IN、EXISTS、NOT、ALL、ANY

赋值运算符:=

字符串运算符:+

比较运算符:=、>、<、>=、<=、<>

位运算符:&、|、^

复合运算符:+=、-=、/=、%=、*=

--已知长方形的长和宽,求长方形的周长和面积
declare @c int = 10
declare @k int = 5
declare @zc int
declare @area int
set @zc = (@c+@k)*2
set @area = @c*@k
print '长方形周长:'+ convert(varchar(10),@zc)
print '长方形面积:'+ convert(varchar(10),@area)
--
print '长方形周长:'+ cast(@zc as varchar(10))
print '长方形面积:'+ cast(@area as varchar(10))
--C#或者Java中数字与字符串相加会进行字符串的拼接,但在C#中会报错


--(2)查询银行卡状态为正常,并且余额超过10万的银行卡信息
select * from BankCard where CardState=1 and CardMoney>100000
--(3)查询出银行卡状态为1或者余额为0的银行卡信息
select * from BankCard where CardState=1 or CardMoney=0
--(4)查询出姓名中含有‘刘’的账户信息以及银行卡信息
select * from AccountInfo 
inner join BankCard on AccountInfo.AccountId = BankCard.AccountId
where RealName like '%刘%' 
--(5)查询出余额在2000-5000之间的银行卡信息
select * from BankCard where CardMoney>=2000 and CardMoney<=5000
select * from BankCard where CardMoney between 2000 and 5000
--(6)查询出银行卡状态为冻结或者注销的银行卡信息
select * from BankCard where BankCard.CardState in(3,4)
--(7)关羽身份证号:145787687,关羽到银行来开户,
--查询身份证账户表是否存在,不存在则进行开户开卡,存在则不开户直接开卡
declare @AccountId int 
if EXISTS(select AccountId from AccountInfo where AccountCode='145787687')
	begin
		select @AccountId=(select AccountId from AccountInfo where AccountCode='145787687')
		insert into BankCard(CardNo,AccountId,CardPwd,CardMoney,CardState,CardTime)
		values('36787887576754',@AccountId,'123456',0,1,GETDATE())
	end
else
	begin
		insert into AccountInfo(AccountCode,AccountPone,RealName,OpenTime)
		values('145787687','15765754135','关羽',GETDATE())
		set @AccountId = @@IDENTITY
		insert into BankCard(CardNo,AccountId,CardPwd,CardMoney,CardState,CardTime)
		values('3678788757675',@AccountId,'123456',0,1,GETDATE())
	end
--扩展:上面需求添加一个限制即一个人最多只能开3张银行卡
declare @AccountId int  --账户编号
declare @CardCount int  --银行卡数目
if EXISTS(select AccountId from AccountInfo where AccountCode='145787687')
	begin
		select @AccountId=(select AccountId from AccountInfo where AccountCode='145787687')
		select @CardCount = (select COUNT(*) from BankCard where AccountId=@AccountId)
		if @CardCount<=2
			begin
				insert into BankCard(CardNo,AccountId,CardPwd,CardMoney,CardState,CardTime)
				values('36787887576754',@AccountId,'123456',0,1,GETDATE())
			end
		else
			begin
				print '您名下的银行卡太多了,最多只能有3张银行卡'
			end
	end
else
	begin
		insert into AccountInfo(AccountCode,AccountPone,RealName,OpenTime)
		values('145787687','15765754135','关羽',GETDATE())
		set @AccountId = @@IDENTITY
		insert into BankCard(CardNo,AccountId,CardPwd,CardMoney,CardState,CardTime)
		values('3678788757675',@AccountId,'123456',0,1,GETDATE())
	end
--(8)查询银行卡账户余额,是不是所有账户余额都超过了3000
if 3000<All(select CardMoney from BankCard)
	begin
		print'所有的银行卡余额都超过了3000'
	end
else
	begin
		print'不是所有的银行卡余额都超过了3000'
	end
--(9)查询银行卡账户余额,是否含有账户余额超过300000的信息
if 300000<ANY(select CardMoney from BankCard)
	begin
		print'有的银行卡余额超过了300000'
	end
else
	begin
		print'没有银行卡余额超过了300000'
	end

4、流程控制

(1)选择分支结构

        1、if-else结构

某用户银行卡号为:,该用户执行取钱操作,取钱5000元,余额充足则进行取钱操作,并提示‘取钱成功’,否则提示‘余额不足’

       
--(1)某用户银行卡号为:876545365656657,该用户执行取钱操作,取钱5000元,余额充足则进行取钱操作,并提示‘取钱成功’
--否则提示‘余额不足’

declare @balance money
select @balance = (select CardMoney 余额 from BankCard where CardNo = '876545365656657')
if @balance>=5000
	begin
		update BankCard set CardMoney=CardMoney-5000
		insert into CardExchange(CardNo,MoneyInBank,MoneyOutBank,ExchangeTime)
		values('876545365656657',0,5000,GETDATE())
		print '取钱成功'
	end
else
	begin
		print '余额不足'
	end
        2、case-when结构
--查询银行卡信息,将银行卡状态1,2,3,4分别转换为汉字“正常、挂失、冻结、注销”,
--并且根据银行卡余额显示银行卡等级
--30万以下为“普通用户”,30万及以上为“VIP用户”
--显示列分别为卡号,身份证,姓名,余额,用户等级,银行卡状态
select CardNo 卡号,AccountCode 身份证,RealName 姓名,CardMoney 余额,
case 
	when CardMoney>=300000 then 'VIP用户'
	else '普通用户'
		
end 用户等级,
case CardState
	when 1 then '正常'
	when 2 then '挂失'
	when 3 then '冻结'
	when 4 then '注销'
	else '异常'
end 银行卡状态
from BankCard
inner join AccountInfo on BankCard.AccountId=AccountInfo.AccountId

 

(2)循环结构

--循环结构---------------------------
--(1)循环打印1-10
declare @i int = 1
while @i<=10
	begin
		print @i
		set @i=@i+1
	end
--(2)循环打印九九乘法表
--特殊字符:char(9):制表符 char(10):换行符
declare @a int =1
declare @b int =1
declare @str varchar(1000) =''
while @a<=9
	begin
		while @b<=@a
		begin
			set @str = @str + convert(varchar(10),@a)+'x'+ convert(varchar(10),@b)+'='+convert(varchar(10),@a*@b)+char(9)
			set @b+=1
		end
		print @str
		set @b =1
		set @a+=1
		set @str = ''
	end

 

5、子查询

--(1)赵云的银行卡号为:4235879656576754
--查询出余额比赵云多的银行卡信息,显示卡号、身份证、姓名、余额
--方案一
declare @balance1 money
select @balance1 = (select CardMoney from BankCard where CardNo = '4235879656576754')
select CardNo 卡号,AccountCode 身份证,RealName 姓名,CardMoney 余额 from BankCard
inner join AccountInfo on BankCard.AccountId=AccountInfo.AccountId
where CardMoney>@balance1
--方案二:子查询
select CardNo 卡号,AccountCode 身份证,RealName 姓名,CardMoney 余额 from BankCard
inner join AccountInfo on BankCard.AccountId=AccountInfo.AccountId
where CardMoney>(select CardMoney from BankCard where CardNo = '4235879656576754')

--(2)从所有账户信息中查询出余额最高的交易明细(存钱取钱信息)
--如果多个人余额一样并且都是最高,下面查询只能查出一个
select * from CardExchange where CardNo = (select top 1 CardNo from BankCard order by CardMoney desc)
--如果多个人余额一样并且都是最高,需要都查出来
select * from CardExchange where CardNo in 
(select CardNo from BankCard where CardMoney=(select MAX(CardMoney) from BankCard))

--(3)查询有取款记录的银行卡及账户信息,显示卡号、身份证、姓名、余额
select CardNo 卡号,AccountCode 身份证,RealName 姓名,CardMoney 余额 from AccountInfo 
inner join BankCard on AccountInfo.AccountId = BankCard.AccountId
where CardNo in(select CardNo from CardExchange where MoneyOutBank>0)

--(4)查询出没有存款记录的银行卡及账户信息,显示卡号,身份证,姓名,余额
select CardNo 卡号,AccountCode 身份证,RealName 姓名,CardMoney 余额 from AccountInfo 
inner join BankCard on AccountInfo.AccountId = BankCard.AccountId
where CardNo not in(select CardNo from CardExchange where MoneyInBank>0 )

--(5)关羽的银行卡号为“876545365656657”,查询当天是否有收到转账
if exists(select * from CardTransfer where 
CardNoIn = '876545365656657' and CONVERT(varchar(22),GETDATE(),23) = CONVERT(varchar(22),TransferTime,23))
	begin
		print '当天有收到转账'
	end
else print '当天没有收到转账'

--(6)查询出交易次数(存款取款操作)最多的银行卡账户信息,
--显示:卡号,身份证,姓名,余额,交易次数
--方案1:该种方案假如有多个相同交易次数则只能显示一个
select top 1 BankCard.CardNo 卡号,AccountCode 身份证,RealName 姓名,CardMoney 余额,交易次数 from AccountInfo 
inner join BankCard on AccountInfo.AccountId = BankCard.AccountId
inner join (select COUNT(*) 交易次数,CardNo from CardExchange 
group by CardNo) Temp on BankCard.CardNo = Temp.CardNo
order by 交易次数 desc
--方案2
select  BankCard.CardNo 卡号,AccountCode 身份证,RealName 姓名,CardMoney 余额,交易次数 from AccountInfo 
inner join BankCard on AccountInfo.AccountId = BankCard.AccountId
inner join (select COUNT(*) 交易次数,CardNo from CardExchange 
group by CardNo) Temp on BankCard.CardNo = Temp.CardNo
where 交易次数 = 
(select MAX(交易次数) from (select COUNT(*) 交易次数,CardNo from CardExchange 
group by CardNo) temp1)

--(7)查询出没有转账交易记录的银行账户信息,显示卡号,身份证,姓名,余额
select  BankCard.CardNo 卡号,AccountCode 身份证,RealName 姓名,CardMoney 余额 from AccountInfo 
inner join BankCard on AccountInfo.AccountId = BankCard.AccountId
where BankCard.CardNo not in(select CardNoIn from CardTransfer) 
and BankCard.CardNo not in(select CardNoOut from CardTransfer)

6、分页

--分页
--假设每页5条数据
--查询第一页
select top 5 * from Student
--等价于
select top 5 * from Student where StuId not in(select top 0 StuId from Student)
--查询第二页
select top 5 * from Student where StuId not in(select top 5 StuId from Student)
--查询第三页
select top 5 * from Student where StuId not in(select top 10 StuId from Student)
 --归纳规律为:
select top 页码大小 * from Student where StuId not in(select top 页码大小*(当前页-1) StuId from Student)

--将页码大小与当前页做成变量
--分页方案1:top方式分页,当数据量大时,效率不高
 declare @PageSize int = 6
 declare @PageIndex int = 1
 select top(@PageSize) * from Student where StuId not in(select top (@PageSize*(@PageIndex-1)) StuId from Student)

--分页方案2:使用row_number分页
 --规律归纳为:
 select * from
 (select ROW_NUMBER() OVER(order by StuId) ROWID,* from Student) TEMP
 where ROWID between 页码大小*(当前页-1)+1 and 当前页*页码大小
 --代码表示如下:
 declare @PageSize int = 5
 declare @PageIndex int = 2
 select * from
 (select ROW_NUMBER() OVER(order by StuId) ROWID,* from Student) TEMP
 where ROWID between @PageSize*(@PageIndex-1)+1 and @PageIndex*@PageSize

7、事务

        1、概念

                将多步操作捆绑在一起,这样的多步操作要么全部成功,要么全部失败

        2、作用

                使用事务可以确保数据库的一致性和完整性,避免数据出现异常或不一致的情况

        3、代码示例

        @@ERROR会在每执行一句SQL语句存入一个值,如果执行成功则为0,执行失败则为错误代码

--事务
 --(1)假设刘备取款6000,(添加Check约束,设置账户余额必须>=0),
 --要求:使用事务实现,修改余额和添加取款记录两步操作使用事务
 alter table BankCard add constraint ck_money check(CardMoney>=0)
 print @@error
 
 begin transaction
 declare @myError int = 0
 update BankCard set CardMoney = CardMoney - 6000 where CardNo = '423556566576754'
 set @myError += @@ERROR
 insert into CardExchange(CardNo,MoneyInBank,MoneyOutBank,ExchangeTime)
 values('423556566576754',0,6000,GETDATE())
 set @myError += @@ERROR
 if @myError = 0
	begin
		commit transaction
		print '取款成功'
	end
 else
	begin
		rollback transaction
		print '取款失败'
	end

	select * from CardExchange
	select * from BankCard

--(2)假设刘备向张飞转账1000元,(添加Check约束,设置账户余额必须>=0)
 --分析步骤有三步:
 --(1):张飞添加1000元(2)刘备扣除1000元(3)生成转账记录      使用事务解决此问题
begin transaction
declare @ExeError int = 0
update BankCard set CardMoney = CardMoney+1000 where CardNo = '255676776785643'
set @ExeError += @@ERROR
update BankCard set CardMoney = CardMoney-1000 where CardNo = '423556566576754'
set @ExeError += @@ERROR
insert into CardTransfer(CardNoOut,CardNoIn,TransferMoney,TransferTime)
values('423556566576754','255676776785643',1000,GETDATE())
set @ExeError += @@ERROR
if @ExeError = 0
	begin
		commit transaction
		print '转账成功'
	end
 else
	begin
		rollback transaction
		print '转账失败'
	end

8、索引

作用:提高检索查询效率

分类:按存储结构区分:”聚集索引(聚类索引)“、”非聚集索引(非聚类索引)“

聚集索引:根据数据行的键值  

9、视图

10、游标

11、函数

12、触发器

13、存储过程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值