【数据库-汇总】SQL SERVER数据库
1.sql sever增删改相关
-- 切换数据库
-- use 数据库名;
1.1创建部门表:
create table Department
(
-- 部门编号,primary key:主键,identity(1,1),自动增长,初始值1,增长步长1
DepartmentId int primary key identity(1,1),
-- 部门名称
DepartmentName nvarchar(50) not NULL,
-- 部门描述
DepartmentRemark text
)
说明:
-- char:定长,char(10),无论存储数据是否真的到了10个字节,都要占用10个字节。
-- char(10)存储'ab',仍然占用10个字节。
-- varchar:变长,varchar(10),最多占用10个字节。
-- varchar(10)存储'ab',占用2个字节
-- text长文本
-- char,varchar,text前面加n:存储unicode字符,对中文友好
-- varchar(100):存储100个字母或者50个汉字。
-- nvarchar(100):存储100个字母或者100个汉字。
创建职级表[Rank]:
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
(
People 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 smalldatetime not null,-- 生日
PeopleSalary decimal(12,2) check(PeopleSalary>=1000 and PeopleSalary<=10000000) not null,-- 月薪
-- unique代表唯一约束,为数据提供唯一性保证
PeoplePhone varchar(20)unique not null,-- 电话
PeopleAddress nvarchar(100)-- 地址
-- datetime和smalldatechar(100)都可以表示时间类型,getdate()用于获取系统当前时间,default()设置默认值
PeopleAddTime smalldatetime default(getdate()) -- 添加时间
)
1.2修改表结构:
- 添加字段(列)
-- alter table 表名 add 新列名 数据类型
alter table people add PeopleMail varchar(200)
- 删除字段(列)
-- alter table 表名 drop column PeopleMail
alter table People drop column PeopleMail
- 修改字段(列)
-- alter table 表名 alter column 列名 数据类型
alter table People alter column PeopleAddress varchar(200)
1.3维护约束(删除,添加):
-- 删除约束
-- alter table 表名 drop constraint 约束名
-- 删除月薪的约束
alter table People drop constraint CK_PeopleSa_34C8D9D1
约束添加:
-- 添加约束(check约束)
-- alter table People add constraint 约束名 check()
-- 添加工资字段约束,工资必须在1000-1000000之间
alter table People add constraint CK_People_PeoPleSal
check(PeopleSalary>=1000 and PeopleSalary<=1000000)
-- 添加约束(主键)
--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.4数据插入:
-- insert into 表名(column1,column2,column3…)value(…,…,…,)
1.5修改数据:
-- 语法
-- update 表名 set 字段1=值1,字段2=值2 where 条件
-- 工资调整,每个人加薪1000
update People set PeopleSalary=PeopleSalary+1000
-- 将员工编号为7的人加薪500
update People set PeopleSalary=PeopleSalary+500 where PeopleId=7
-- 将软件部(部门编号1)人员工资低于10000的调整成10000
update People set PeopleSalary=10000 where DepartmentId=1 and PeopleSalary<10000
-- 修改刘备的工资是以前的两倍,并且把刘备的地址改成北京
update People set PeopleSalary=PeopleSalary*2,PeopleAddress='北京' where PeopleName='刘备'
1.6删除数据:
-- 语法:
--delete from 表名 where 条件
-- 删除员工表所有数据
delete from People
-- 删除市场部(部门编号3)工资大于10000的人
delete from People where DepartmentId=3 and PeopleSalary>10000
注:关于删除(drop,truncate,delete)
-- 删除表对象
drop table People
-- 删除数据(清空数据)
-- 删除所有数据,表对象即表结构依然存在
truncate table People delete from People
-- truncate和delete区别
-- truncate清空所有数据不能有条件,delete可以删除所有数据也可以带条件,删除符合条件的数据
-- 自动编号:
-- 假设表中自动编号为1,2,3,4,5
-- 使用truncate清空数据之后再添加数据,编号仍然是1,2,3,4,5,
-- 使用delete删除数据,删除的自动编号将永远不存在了
-- 如果使用delete删除了所有的数据之后再添加数据,编号就变成了,6,7,8,9,10
2.查询相关:
2.1简单查询:
-- 查询所有列所有行
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.2条件查询:
SQL中常用运算符
2.3多条件查询
-- 查询月薪大于等于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之间的员工信息(多条件)
select * from People where PeopleSalary>=10000 and PeopleSalary<=20000
select * from People where PeopleSalary between10000 and 20000
-- 查询地址在武汉或者北京的员工信息
select * from People where PeopleAddress='武汉' or PeopleAddress='北京'
select * from People where PeopleAddress in('武汉' ,'北京')
2.4排序:
-- 查询所有员工信息,根据工资排序,降序
-- asc升序(默认),desc降序
select * from People order by PeopleSalary desc
-- 查询所有员工信息,根据名字长度排序(降序)
select * from People order by .len(PeopleName) desc
-- 查询出工资最高的5个人的信息
select top 5 * from People order by PeopleSalary decs
-- 查询出工资最高的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>='1989-12-31'
select * from People where People Birth 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(getdatea())-year(peopleBirth)>=30 and year(getdate())-year(PeopleBirth)<=40)
and
(PeopleSalary between 15000 and 30000)
select * from People where
(year(getdatea())-year(peopleBirth) between 30 and 40)
and
(PeopleSalary between 15000 and 30000)
-- 查询出星座是巨蟹座的员工信息(6.22-7.22)
select * from People where
(month(PeopleBirth)=6 and day(PeopleBirth)>=22)
or
(month(PeopleBirth)=7 and day(PeopleBirth)<=22)
2.5子查询:
-- 查询出工资比赵云高的信息
select * from People where PeopleSalary>
(select PeopleSalary from People where PeopleName='赵云')
-- 查询出和赵云在一个城市的人的信息
select * from People where PeopleAddress=
(select PeopleAddress from People where PeopleName='赵云')
-- 查询出生肖是鼠的人员信息
-- 鼠 (子)、牛 (丑)、虎 (寅)、兔 (卯)、龙 (辰)、蛇 (巳)、马 (午)、羊 (未)、猴 (申)、鸡 (酉)、狗 (戌)、猪 (亥)
-- 出生年份%12 12生肖对应——>4 5 6 7 8 9 10 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 '猪'
end 生肖
from People
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 '猪'
end 生肖
from People
2.6模糊查询:
- %:代表匹配0个字符、1个字符或多个字符
- _:代表匹配有且只有1个字符
- []:代表匹配范围内
- [^]:代表匹配不在范围内
(1)查询姓刘的员工信息
select * from People where PeopleName like '刘%'
(2)查询名字中含有尚的员工信息
select * from People where PeopleName like '%尚%'
(3)查询名字中含有“尚”或者“史”的员工信息
select * from People where PeopleName like '%尚%' or '%史%'
(4)查询出姓刘的员工信息(名字两个字)
select * from People where PeopleName like '刘_'
-- SUBSTRING(字符串',开始,个数)
-- SUBSTRING('hello,world',3,1) -- l
select * from People where SUBSTRING(PeopleName,1,1)='刘'
and len(PeopleName)=2
-- 查询名字最后一个字为香,名字一共是三个字的员工信息
select * from People where SUBSTRING(PeopleName,3,1)='香'
and len(PeopleName)=3
-- 查询出电话号码,开头为138的员工信息
select * from People where PeoplePhone like '138%'
-- 查询出电话号码开头为138的,第四位好像是7或8,最后一个号码是5
select PeoplePhone from People where PeoplePhone like '138[7,8]%5'
-- 查询出电话号码开头为138的,第四位好像是2-5之间,最后一个号码不是2和3
select PeoplePhone from People where PeoplePhone like '138[2,3,4,5]%[^2,3]'
select PeoplePhone from People where PeoplePhone like '138[2-5]%[^2-3]
2.7聚合函数:
SQL SERVER中聚合函数主要有:
count:求数量
max:求最大值
min:求最小值
sum:求和
avg:求平均值
一、聚合函数举例应用
(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 round(AVG(PeopleSalary),2) 平均工资 from People
-- 四舍五入,保留两位小数
select round(25.5555,2)-- 25.5600
(6)求数量,最大值,最小值,总和,平均值,在一行显示
select COUNT(*) 数量,MAX(PeopleSalary) 最高工资,MIN(PeopleSalary) 最低工资,SUM(PeopleSalary) 工资总和,round(AVG(PeopleSalary),2) 平均工资 from People
(7)查询武汉地区的人数量,工资最大值,最小值,总和,平均值,在一行显示
select COUNT(*) 数量,MAX(PeopleSalary) 最高工资,MIN(PeopleSalary) 最低工资,SUM(PeopleSalary) 工资总和,round(AVG(PeopleSalary),2) 平均工资 from People where PeopleAddress='武汉'
(8)求出工资比平均工资高的人员信息
select * from People where PeopleSalary>(select round(AVG(PeopleSalary),2) from People)
(9)求数量,年龄最大值,年龄最小值,年龄总和,年龄平均值在一行显示
-- 方案一:
select COUNT(*) 数量,
year(getdate())-year(PeopleBirth) 年龄,
MAX(year(getdate())-year(PeopleBirth)) 年龄最大值,
MIN(year(getdate())-year(PeopleBirth)) 年龄最小值,
SUM(year(getdate())-year(PeopleBirth)) 年龄总和,
round(AVG(year(getdate())-year(PeopleBirth))) 年龄平均值
from People
-- 方案二:DATEDIFF(单位,被减数,减数)
select COUNT(*) 数量,
DATEDIFF(year,PeopleBirth,getdate()) 年龄,
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以上' 月薪,'男' 性别,
COUNT(*) 数量,
DATEDIFF(year,PeopleBirth,getdate()) 年龄,
MAX(DATEDIFF(year,PeopleBirth,getdate())) 年龄最大值,
MIN(DATEDIFF(year,PeopleBirth,getdate())) 年龄最小值,
SUM(DATEDIFF(year,PeopleBirth,getdate())) 年龄总和,
AVG(DATEDIFF(year,PeopleBirth,getdate())) 年龄平均值
from People
where PeopleSalary >10000 and PeopleSex='男'
(11)统计出所在地在“武汉或上海”的所有女员工数量以及最大年龄,最小年龄和平均年龄
select '武汉或上海' 地区,'女' 性别,
COUNT(*) 数量,
DATEDIFF(year,PeopleBirth,getdate()) 年龄,
MAX(DATEDIFF(year,PeopleBirth,getdate())) 年龄最大值,
MIN(DATEDIFF(year,PeopleBirth,getdate())) 年龄最小值,
SUM(DATEDIFF(year,PeopleBirth,getdate())) 年龄总和,
AVG(DATEDIFF(year,PeopleBirth,getdate())) 年龄平均值
from People
where PeopleAddress in('武汉','上海') and PeopleSex='女'
(12)求出年龄比平均年龄高的人员信息
select * from People where DATEDIFF(year,PeopleBirth,getdate())>
(select AVG(DATEDIFF(year,PeopleBirth,getdate())) from People)
2.8分组查询:
(1)根据员工所在地区分组统计员工人数,员工工资总和,平均工资,最高工资和最低工资
-- group by:
select PeopleAddress 地区,COUNT(*) 数量,MAX(PeopleSalary) 最高工资,MIN(PeopleSalary) 最低工资,SUM(PeopleSalary) 工资总和,ROUND(AVG(PeopleSalary),2) 平均工资 from People
group by PeopleAddress
(2)根据员工所在地区分组统计员工人数,员工工资总和,平均工资,最高工资和最低工资,1985年及以后出生的员工不参与统计
select PeopleAddress 地区,COUNT(*) 数量,MAX(PeopleSalary) 最高工资,MIN(PeopleSalary) 最低工资,SUM(PeopleSalary) 工资总和,ROUND(AVG(PeopleSalary),2) 平均工资 from People
where PeopleBirth<'1985-1-1'
group by PeopleAddress
(3)根据员工所在地区分组统计员工人数,员工工资总和,平均工资,最高工资和最低工资,要求筛选出员工人数至少在2人及以上的记录,并且1985年及以后出生的员工不参与统计
-- having 、where的使用
select PeopleAddress 地区,COUNT(*) 数量,MAX(PeopleSalary) 最高工资,MIN(PeopleSalary) 最低工资,SUM(PeopleSalary) 工资总和,ROUND(AVG(PeopleSalary),2) 平均工资 from People
where PeopleBirth<'1985-1-1'
group by PeopleAddress
having COUNT(*)>=2
2.9多表查询:
--笛卡尔乘积
select * from People,Department -- 查询结果将Department所有的记录和People表所有记录一次排列组合形成的结果
-- 简单多条查询
-- 查询员工信息,显示部门名称
select * from People,Department
where People.DepartmentId=Department.DepartmentId
-- 查询员工信息,显示部门名称,显示职级名称
select * from People,Department,[rank]
where People.DepartmentId=Department.DepartmentId
and People.RankId=[Rank].RankId
2.10内连接查询:
-- 查询员工信息,显示部门名称
select * from People inner join Department
on People.DepartmentId=Department.DepartmentId
-- 查询员工信息,显示部门名称,显示职级名称
select * from People
inner join Departmenton on People.DepartmentId=Department.DepartmentId
inner join [rank] on People.RankId=[Rank].RankId
简单多表查询和内连接共同的特点:不符合主外键关系的数据不会被显示出来
3.连接查询
3.1外连接(左外连left join,右外连right join,全外连full join):
-- 左外联:以左表为主表进行数据显示,主外键关系找不到的数据null取代
-- 查询员工信息,显示部门名称
select * from People
left join Department on People.DepartmentId=Department.DepartmentId
-- 查询员工信息,显示职别名称
select * from People
left join [Rank] on People.RankId=[Rank].RankId
-- 查询员工信息,显示部门名称,显示职级名称
select * from People
left join Departmenton on People.DepartmentId=Department.DepartmentId
left join [rank] on People.RankId=[Rank].RankId
-- 右连接:A left join B =B right join A
-- 下面两个查询含义相同
select * from People
left join Department on People.DepartmentId=DepartmentId
select * from Department
right join People on People.DepartmentId=DepartmentId
-- 全外联:两张表的数据,无论是否符合关系,都要显示
select * from People
full join Department on People.DepartmentId=DepartmentId
3.2多表查询综合案例:
(1)查询出武汉地区所有的员工信息,要求显示部门名称以及员工的详细资料(显示中文别名)
select PeopleName 姓名,People.DepartmentId 部门编号, DepartmentName 部门名称,
PeopleSex 性别,PeopleBirth 生日,
PeopleSalary 月薪,PeoplePhone 电话,PeopleAddress 地区
from People left join Department on People.DepartmentId=Department.DepartmentId
where PeopleAddess='武汉'
(2)查询出武汉地区所有的员工信息,要求显示部门名称,职级名称以及员工的详细资料
select PeopleName 姓名,People.DepartmentId 部门编号, DepartmentName 部门名称,
PeopleSex 性别,PeopleBirth 生日,
PeopleSalary 月薪,PeoplePhone 电话,PeopleAddress 地区
from People left join Department on People.DepartmentId=Department.DepartmentId
left join [Rank] on People.RankId=[Rank].RankId
where PeopleAddess='武汉'
(3)根据部门分组统计员工人数,员工工资总和,平均工资,最高工资和最低工资
select DepartmentName 部门名称,count(*) 员工人数,sum(PeopleSalary) 员工工资总和,avg(PeopleSalary) 平均工资,max(PeopleSalary) 最高工资,min(PeopleSalary) 最低工资
from People
left join Department
on People.DepartmentId=Department.DepartmentId
group by Department.DepartmentId,DepartmentName
注:如果以名称分组,容易重名
(4)根据部门分组统计员工人数,员工工资总和,平均工资,最高工资和最低工资,平均工资在10000以下的不参与统计,并且根据平均工资降序排列
select DepartmentName 部门名称,count(*) 员工人数,sum(PeopleSalary) 员工工资总和,avg(PeopleSalary) 平均工资,max(PeopleSalary) 最高工资,min(PeopleSalary) 最低工资
from People
inner join Department
on People.DepartmentId=Department.DepartmentId
group by Department.DepartmentId,DepartmentName
having avg(PeopleSalary) >=10000
order by round(avg(PeopleSalary),2) desc
(5)根据部门名称,然后根据职位名称,分组统计员工人数,员工工资总和,平均工资,最高工资和最低工资
select DepartmentName 部门名称,RankName 职位名称,count(*) 员工人数,sum(PeopleSalary) 员工工资总和,avg(PeopleSalary) 平均工资,max(PeopleSalary) 最高工资,min(PeopleSalary) 最低工资
from People
inner join Department on People.DepartmentId=Department.DepartmentId
inner join [Rank] on People.RankId=[Rank].RankId
group by Department.DepartmentId,DepartmentName,[Rank].RankId,RankName
3.3自连接(自己连自己)
DeptId |
DeptName |
parenId |
1 |
软件部 |
0 |
2 |
硬件部 |
0 |
3 |
软件研发部 |
1 |
4 |
软件实施部 |
1 |
5 |
硬件研发部 |
2 |
6 |
硬件测试部 |
2 |
-- 起别名
select A.DeptId 部门编号,A.DeptName 部门名称,B.DeptName 上级部门 from Dept A
inner join Dept B on A.ParenId=B.DeptId
4.数据库设计
4.1数据库结构设计三范式
第一范式(1NF)是指表中的字段都是不可再分的原子属性,同时表需要有一个主键。
修改:
第二范式(2NF)首先需要满足第一范式,非主键字段必须完全依赖于主键字段,不能只依赖于主键的一部分。
修改:
第三范式(3NF)首先需要满足第二范式,非主键字段不能依赖于其他非主键字段。为了提高查询性能可以降低规范化的级别,也就是反规范化(Denormalization)。
修改:
4.2表关系(一对一,一对多,多对多)
一对多(专业表、学生表)-- 可合并
一对一(学生基本信息(学号、姓名、性别),学生详细信息(电话、邮箱、地址))-- 添加字段关联
多对多(学生信息,课程信息)-- 可通过一张表关联
4.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,-- 身份证号码
AccountPhone varchar(20) not null,-- 电话号码
RealName varchar(20) noy null,-- 真实姓名
OpenTime smalldatetime not null,-- 开户时间
)
create table BankCard --银行卡
(
CardNo varchar(30) primary key, -- 银行卡卡号
AccountId int primary key identity(1,1), -- 账户编号(域账户信息表形成主外键关系)
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) not null,-- 银行卡号(与银行卡表形成主外键关系)
MoneyInBank money not null,-- 存钱金额
MoneyOutBank money not null, -- 取钱金额
ExchangTime 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) not null, -- 银行卡号(与银行卡表形成主外键关系)
CardState int not null,-- 银行卡原始状态
NewState int not null,-- 银行卡新状态
StateWhy varchar(200) not null,-- 状态变化原因
StateTime smalldatetime not null,-- 记录产生时间
)
案例:
为刘备,关羽,张飞三个人进行开户开卡的操作
刘备身份证:420107198905064135
关羽身份证:420107199507104133
张飞身份证:420107199602034138
insert into AccountInfo(AccountCode,AccountPhone,RealName,OpenTime)
values('420107198905064135','13555687749','刘备',GETDATE())
insert into BankCard(CardNo,AccountId,CardPwd,CardMoney,CardState,CardTime)
values('6225125478544587',1,'123456',0,1)
insert into AccountInfo(AccountCode,AccountPhone,RealName,OpenTime)
values('420107199507104133','13555687749','关羽',GETDATE())
insert into BankCard(CardNo,AccountId,CardPwd,CardMoney,CardState,CardTime)
values('6225125478544698',2,'123456',0,1)
insert into AccountInfo(AccountCode,AccountPhone,RealName,OpenTime)
values('420107199602034138','13555687749','张飞',GETDATE())
insert into BankCard(CardNo,AccountId,CardPwd,CardMoney,CardState,CardTime)
values('6225125478544709',3,'123456',0,1)
刘备存钱:2000元
update BankCard set CardMoney=CardMoney+2000 where CardNo='6225125478544587'
insert into CardExchange(CardNo,MoneyInBank,MoneyOutBank,ExchangeTime)
values('6225125478544587',2000,0,GETDATE())
转账:刘备给张飞转账1000元
update BankCard set CardMoney - 1000 Where CardNo='6225125478544587'
update BankCard set CardMoney + 1000 Where CardNo='6225125478544709'
insert into CardTransfer(CardNoOut,CardNoIn,TransferMoney,TransferTime)
Values('6225125478544587','6225125478544709',1000,GETDATE())
5.使用sql进行信息打印
5.1变量
①局部变量:以@开头,先声明,再赋值
declare @str varchar(20)
set @str ='I like sql'
-- select @str='i like sql'
print @str
-- set 和select进行赋值时的区别
-- set:赋值变量指定的值
-- select:一般用于表中查询出的数据赋值给变量,如果查询结果有多条,取最后一条赋值
-- exp:select @a=字段名 from 表名
-- 当前表最后一行的某个字段的值给@a
②全局变量:以@@开头,由系统进行定义和维护
@@CONNECTIONS
--返回自上次启动以来连接或试图连接的次数。
@@CURSOR_ROWS
--返回连接上最后打开的游标中当前存在的合格行的数量(返回被打开的游标中还未被读取的有效数据行的行数)
@@DATEFIRST
--返回每周第一天的数字
@@ERROR
--返回最后执行的SQL 语句的错误代码。
@@FETCH_STATUS
--返回被 FETCH 语句执行的最后游标的状态,而不是任何当前被连接打开的游标的状态。
@@IDENTITY
--返回最后插入的标识值
@@LANGID
--返回当前所使用语言的本地语言标识符(ID)。
@@LANGUAGE
--返回当前使用的语言名。
@@LOCK_TIMEOUT
--返回当前会话的当前锁超时设置,单位为毫秒。
@@PROCID
--返回当前过程的存储过程标识符 (ID) 。
@@ROWCOUNT
--返回受上一语句影响的行数。
@@SERVERNAME
--返回运行 的本地服务器名称。
@@SPID
--返回当前用户进程的服务器进程标识符 (ID)。
@@TRANCOUNT
--返回当前连接的活动事务数。
@@VERSION
--返回当前安装的日期、版本和处理器类型。
@@CPU_BUSY
--返回自SQL Server 最近一次启动以来CPU 的工作时间其单位为毫秒
@@DATEFIRST
--返回使用SET DATEFIRST 命令而被赋值的DATAFIRST 参数值SET DATEFIRST,命令用来指定每周的第一天是星期几
@@DBTS
--返回当前数据库的时间戳值必须保证数据库中时间戳的值是惟一的
@@ERROR
--返回执行Transact-SQL 语句的错误代码
@@FETCH_STATUS
--返回上一次FETCH 语句的状态值
@@IDLE
--返回自SQL Server 最近一次启动以来CPU 处于空闭状态的时间长短单位为毫秒
@@IO_BUSY
---返回自SQL Server 最近一次启动以来CPU 执行输入输出操作所花费的时间其单位为毫秒
@@LANGID
--返回当前所使用的语言ID 值
@@LANGUAGE
--返回当前使用的语言名称
@@LOCK_TIMEOUT
--返回当前会话等待锁的时间长短其单位为毫秒
@@MAX_CONNECTIONS
--返回允许连接到SQL Server 的最大用户连接数目
@@MAX_PRECISION
--返回decimal 和numeric 数据类型的精确度
@@NESTLEVEL
--返回当前执行的存储过程的嵌套级数初始值为0
@@OPTIONS
--返回当前SET 选项的信息
@@PACK_RECEIVED
--返回SQL Server 通过网络读取的输入包的数目
@@PACK_SENT
--返回SQL Server 写给网络的输出包的数目
@@PACKET_ERRORS
--返回网络包的错误数目
@@PROCID
--返回当前存储过程的ID 值
@@REMSERVER
--返回远程SQL Server 数据库服务器的名称
@@SERVICENAME
--返回SQL Server 正在其下运行的注册表项的名称
@@SPID
--返回当前用户处理的服务器处理ID 值
@@TEXTSIZE
--返回SET 语句的TEXTSIZE 选项值SET 语句定义了SELECT 语句中text 或image数据类型的最大长度基本单位为字节
@@TIMETICKS
--返回每一时钟的微秒数
@@TOTAL_ERRORS
--返回磁盘读写错误数目
@@TOTAL_READ
--返回磁盘读操作的数目
@@TOTAL_WRITE
--返回磁盘写操作的数目
@@TRANCOUNT
--返回当前连接中处于激活状态的事务数目
5.2实例:
(1)为赵云此人进行开户操作,赵云身份证:420107199904054233
insert into AccountInfo(AccountCode,AccountPhone,RealName,OpenTime)
values('420107199904054233','13555687766','赵云',GETDATE())
declare @AccountId int
set @AccountId=@@IDENTITY
insert into BankCard(CardNo,AccountId,CardPwd,CardMoney,CardState,CardTime)
values('6225125478544710',@AccountId,'123456',0,1)
(2)需要求出张飞的银行卡号和余额,张飞身份证:420107199602034138
select CardNo 卡号,CardMoney 余额 from BankCard
inner jion AccountInfo on BankCard.AccountId=AccountInfo.AccountId
where AccountCode ='420107199602034138'
declare @AccountId int
select @AccountId=
(select AccountId from AccountInfo where AccountCode='420107199602034138')
select CardNo 卡号,CardMoney 余额 from BankCard
where AccountId=@AccountId
5.3 go语句
(1)等待go语句之前代码执行结束才能执行后面的代码
-- 例:
create datebase DBTEST1
use DBTEST1
create table AccountInfo --账户信息表
(
AccountId int primary key identity(1,1),-- 账户编号
AccountCode varchar(20) not null,-- 身份证号码
AccountPhone varchar(20) not null,-- 电话号码
RealName varchar(20) not null,-- 真实姓名
OpenTime smalldatetime not null,-- 开户时间
)
-- 执行失败,建库失败未完成,不能使用
create datebase DBTEST1
go -- 等待建库成功,才可以继续执行
use DBTEST1
create table AccountInfo --账户信息表
(
AccountId int primary key identity(1,1),-- 账户编号
AccountCode varchar(20) not null,-- 身份证号码
AccountPhone varchar(20) not null,-- 电话号码
RealName varchar(20) not null,-- 真实姓名
OpenTime smalldatetime not null,-- 开户时间
)
(2)批处理结束的一个标志
declare @num int --@num作用范围全局
set @num =100
set @num =200
go
declare @num1 int --@num1作用范围在两个go之间
set @num1 =100
go
set @num1 =200 -- 不能赋值
6.运算符
6.1 sql中使用的运算符分为7种
- 算数运算符:+、-、*、/、%(模)
- 逻辑运算符:AND 、OR、LIKE、EXISTS()-- 存在、NOT、ALL()-- 所有、ANY()-- 存在
- 赋值运算符:=
- 字符串运算符:+
- 比较运算符:=、>、<、>=、<=、<>(不等于)
- 位运算符:|、&、^
- 符合运算符:+=、-=、/=、%=、*=
6.2运算符示例:
(1)已知长方形的长和宽,求长方形的周长和面积
declare @c int =10
declare @k int =5
declare @zc int
declare @mj int
set @zc=(@c+@k)*2
set @mj=@c*@k
-- print '圆周长:'+cast(varchar(10),@zc)
-- print '圆面积:'+cast(varchar(10),@mj)
print'圆周长:'+Convert(@zc as varchar(10))
print'圆面积:'+Convert(@mj as varchar(10))
(2)查询银行卡状态为冻结,并且余额超过1000000的银行卡信息
select * from BankCard where CardState=3 and CardMoney>1000000
(3)查询出银行卡状态为冻结或者余额等于0的银行卡信息
select * from BankCard where CardState=3 or CardMoney=0
(4)查询出姓名中含有‘刘’的账户信息以及银行卡信息
select * from AccountInfo
inner join BankCard on AccountInfo.AccountId=BankCard.AccountId
where RealName like '%刘%'
(5)关羽身份证号:420107199507104133,关羽到银行来开户,查询身份证在账户表是否存在,不存在则进行开卡,存在则不开户直接开卡
declare @AccountId int
if EXISTS(select * from AccountInfo where AccountId='420107199507104133') -- 存在此人
begin
select @AccountId=
(select AccountId from AccountInfo where AccountId='420107199507104133')
insert into BankCard(CardNo,AccountId,CardPwd,CardMoney,CardState,CardTime)
values('6225125478544721',@AccountId,'123456',0,1)
end
else -- 不存在此人
begin
insert into AccountInfo(AccountCode,AccountPhone,RealName,OpenTime)
values('420107199904054233','13555687766','关羽',GETDATE())
set @AccountId=@@IDENTITY
insert into BankCard(CardNo,AccountId,CardPwd,CardMoney,CardState,CardTime)
values('6225125478544721',@AccountId,'123456',0,1)
end
(6)扩展:上面需求上添加一个限制,即一个人最多只能开3张银行卡
declare @AccountId int -- 账号编号
declare @CardCount int -- 卡数量
if EXISTS(select * from AccountInfo where AccountId='420107199507104133') -- 存在此人
begin
select @AccountId=
(select AccountId from AccountInfo where AccountId='420107199507104133')
select @CardCount=
(select count(*) from BankCard where AccountId=@AccountId)
if @CardCount<=2
begin
insert into BankCard(CardNo,AccountId,CardPwd,CardMoney,CardState,CardTime)
values('6225125478544721',@AccountId,'123456',0,1)
end
else
begin
print '您名下的银行卡太多了,最多只能有3张银行卡'
end
end
else -- 不存在此人
begin
insert into AccountInfo(AccountCode,AccountPhone,RealName,OpenTime)
values('420107199904054233','13555687766','关羽',GETDATE())
set @AccountId=@@IDENTITY
insert into BankCard(CardNo,AccountId,CardPwd,CardMoney,CardState,CardTime)
values('6225125478544721',@AccountId,'123456',0,1)
end
7.流程控制
7.1选择分支结构
(1)某用户银行卡号为“6225547854125656”
该用户执行取钱操作,取钱5000元,余额充足则进行取钱操作
并提示“取钱成功”,否则提示“余额不足”
declare @balance money
select @balance=
(select * from BankCard where BankMoney>=5000)
if @balance>=5000 -- 可以取钱
begin
update BankCard set CardMoney=CardMoney - 5000
where CardNo='6225547854125656'
insert into CardExchange(CardNo,MoneyInBank,MoneyOutBank,ExchangeTime)
values('6225547854125656',0,5000,GETDATE())
print '取钱成功'
end
else -- 不能取钱
begin
print '余额不足'
end
(2)查询银行卡信息,将银行卡状态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 '冻结'
when4 then '注销'
else '异常'
end) 银行卡状态
from BankCard
inner join AccountInfo on BankCard.AccountId=AccountInfo.AccountId
-- 注:
-- case 判断
-- when 修改前 then 修改后
-- when 修改前 then 修改后
-- else 其他
-- end
7.2循环结构(while)
(1)循环打印1-10
declare @i int =1
while @i<=10
begin
print @i
set @i=@i+1
end
(2)循环打印九九乘法表
-- 特殊字符:char(9):制表符
declare @i int =1
while @i<=9
begin
declare @str varchar(1000)=''
declare @j int =1
while @j<=@i
begin
set @str=@str+cast(@j as varchar(1))+'x'+cast(@i as varchar(1))+'='+cast(@j*@i as varchar(2)) +char(9)
set @j=@j+1
end
set @i=@i+1
print @str
end
7.3子查询
(1)关羽的银行卡号为“6225547858741263”
-- 查询出余额比关羽多的银行卡信息,显示卡号,身份证,姓名,余额。
select CardNo 卡号,AccountId 身份证,RealName 姓名,CardMoney 余额 from BankCard
inner join AccountInfo on BankCard.AccountId=Account.AccountId
where CardMoney>(select CardMoney from BankCard where CardNo='6225547858741263')
(2)从所有账户信息中查询出余额最高的交易明细(存钱取钱信息)。
select * from CardExchange CardNo in
(select CardNo from BankCard where CardMoney=
(select MAX(CardMoney) from BankCard))
(3)查询有取款记录的银行卡及账户信息,显示卡号,身份证,姓名,余额
select CardNo 卡号,AccountCode 身份证,RealName 姓名,BankMoney 余额 from BankCard
inner join AccountInfo on BankCard.AccountId=Account.AccountId
where CardNo in (select CardNo from BankExchange where MoneyOutBank>0)
(4)查询出没有存款记录的银行卡及信息,显示卡号,身份证,姓名,余额
select CardNo 卡号,AccountCode 身份证,RealName 姓名,BankMoney 余额 from BankCard
inner join AccountInfo on BankCard.AccountId=Account.AccountId
where CardNo not in (select CardNo from BankExchange where MoneyInBank>0)
(5)关羽的银行卡号为“6225547858741263”,查询当天是否有收到转账
if EXISTS(select * from CardTransfer where CardNoIn='6225547858741263'
and convert(varchar(22),getdate(),23)=convert(varchar(22),transferTime,23))
begin
print '有收到转账'
end
else
begin
print '没有收到转账'
end
(6)查询出交易次数(存款取款操作)最多的银行卡账户信息,显示:卡号,身份证,姓名,余额,交易次数。
方案一:
select top 1 BankCard.CardNo 卡号,AccountId 身份证,RealName 姓名,CardMoney 余额,Temp.myCount 交易次数 from BankCard
inner join AccountInfo on BankCard.AccountId=Account.AccountId
inner join
(select CardNo,count(*) myCount from CardExchange group by CardNo) Temp
on BankCard.CardNo=Temp.CardNo
order by Temp.myCount desc
方案二:
select BankCard.CardNo 卡号,AccountId 身份证,RealName 姓名,CardMoney 余额,Temp.myCount 交易次数 from BankCard
inner join AccountInfo on BankCard.AccountId=Account.AccountId
inner join
(select CardNo,count(*) myCount from CardExchange group by CardNo) Temp
on BankCard.CardNo=Temp.CardNo
where Temp.myCount=
(
select max(Temp.myCount) from
(select CardNo,count(*) from CardExchange group by CardNo) Temp
)
(7)查询出没有转账交易记录的银行卡账户信息,显示卡号,身份证,姓名,余额
select CardNo 显示卡号,AccountCode 身份证,RealName姓名,BankMoney 余额
from AccountInfo
inner join BankCard on AccountInfo.AccountId=BankCard.AccountId
where CardNo not in(select CardNoOut from CardTransfer)
and CardNo not in(select CardNoIn from CardTransfer)
7.4分页
假设每页5条数据
-- 查询第一页
select top 5 * 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)
-- 分页方案一:top方式分页
declare @PageSize int=5
declare @PageIndex int=1
select top (@PageSize) * from Student
where StuId not in(select top @PageSize*(@PageIndex-1) StuId from Student)
-- 方案二:使用row_number分页
-- ROW_NUMBER() 就是生成一个顺序的行号,而他生成顺序的标准,就是后面紧跟的OVER(ORDER BY 字段名)
select * from
(select ROW_NUMBER() over(order by StuId) RowId,* from Student) Temp
where RowId between (当前页-1)*页码大小+1 and 当前页*页码大小
declare @PageSize int=5
declare @PageIndx int=3
select * from
(select ROW_NUMBER() over(order by StuId) RowId,* from Student) Temp
where RowId between (@PageIndx-1)*@PageSize+1 and @PageIndx*@PageSize
7.5事物
简单理解为 相关联的表单操作时需要同步,不然会出现一个表单操作失败,另一个表单成功,导致数据不准确
刘备 420107198905064135 6225125478544587
关羽 420107199507104133 6225547858741263
张飞 420107199302034138 6225547854125656
(1)假设刘备取款6000,(添加check约束,设置账户余额必须>=0),要求:使用事物实现,修改余额和添加取款记录两步操作使用事物
begin transaction -- 使用事务
declare @myError int =0
update BankCard set CardMoney=CardMoney-6000 where CardNo='6225125478544587'
set @myError=@myError+@@ERROR
insert into CardExchange(CardNo,MoneyOutBank,MoneyInBank,ExchangeTime)
values('6225125478544587',0,1,getdate())
set @myError=@myError+@@ERROR
if @myError=0 – 逻辑判断
begin
commit transaction – 成功
print '取款成功'
end
else
begin
rollback transaction – 失败回滚
print '取款失败'
end
*(2)假设刘备向张飞转账1000元,(添加check约束,设置账户余额必须>=0);
-- 分析步骤有三部(1)张飞添加1000元,(2)刘备扣除1000元,(3)生成转账记录
begin transaction
declare @myError int =0
update BankCard set CardMoney=CardMoney-1000 where CardNo='6225125478544587'
set @myError=@Error+@@ERROR
update BankCard set CardMoney=CardMoney+1000 where CardNo='6225547854125656'
set @myError=@Error+@@ERROR
insert into CardTransfer (CardNoOut,CardNoIn,TransferMoney,TransferTime)values('6225125478544587','6225125478544587',1000,getdate())
set @myError=@Error+@@ERROR
if @myError=0
begin
commit transaction
print '转账成功'
end
else
begin
rollback transaction
print '转账失败'
end
注:
commit transaction -- 标志一个成功的隐性事务或显式事务的结束。
rollback transaction -- 将显式事务或隐性事务回滚到事务的起点或事务内的某个保存点。
*8.索引
8.1索引:
提高检索查询效率
聚集索引:物理存储顺序
非聚集索引:逻辑存储顺序
8.2 创建索引的方式(需要另学)
1.通过显式的Create index命令
2.在创建约束时作为隐含的对象
- 主键约束
- 唯一约束
创建索引语法:
create [unique] [clustered | noclustered]
index<index name> on <table or view name>(<column name>[ASC | DESC][,…n])
-- 例:给AccountInfo表中的AccoundCode字段添加索引
create unique noclustered index index_code
on AccountInfo(AccountCode)
-- 索引查看(sys.indexes)
select * from sys.indexes where name='index_code'
-- 删除索引
drop index index_code on AccountInfo
-- 按显示指定索引查询
select * from AccountInfo with(index=index_code)
where AccountCode='420107199507104133'
*9.视图
视图:可以理解为虚拟表,封装SQL语句
-- (1)显示卡号,身份证,姓名,余额
-- 创建视图,实现显示卡号,身份证,姓名,余额
create view View_Account_Card
as
select CardNo 卡号,AccountCode 身份证,RealName 姓名,CardMoney 余额 from BankCard
inner join AccountInfo on BankCard.AccountId=AccountInfo.AccountId
go
如果要进行相应信息查询,不需要编写复杂的SQL语句,直接使用视图,如下:
select * from View_Account_Card
*10.游标
游标:定位到结果集中某一行
游标分类:
(1)静态游标:数据发生变化,游标中数据不变
(2)动态游标:数据发生变化,游标中数据改变,默认值
(3)键集驱动游标:被标识的列发生改变,游标中数据改变,其他列改变,游标中数据不变
-- 创建游标(scroll:滚动游标,没有scroll,只进)
declare mycur cursor scroll
for select MemberAccount from Member
-- 游标打开
open mycur
-- 提取某行数据
fetch first from mycur -- 第一行
fetch last from mycur -- 最后一行
fetch absolute 2 from mycur -- 提取第二行
fetch relative 2 from mycur -- 当前行下移2行
fetch next from mycur -- 下移一行
fetch prior from mycur -- 下移一行
-- 提取游标数据存入变量,进行查询所有列信息
declare @acc varchar(20)
fetch absolute 2 from mycur into @acc
select * from Member where MemberAccount=@acc
-- 遍历游标
fetch absolute 1 from mycur
-- @@fetch_status:0 -- 0-提取成功,1-失败,2-不存在
while @@fetch_status=0
begin
print '提取成功:'+@acc
fetch next from mycur into @acc
end
-- 关闭游标
close mycur
-- 删除游标
deallocate mycur
-- 利用游标进行数据的修改和删除
select * from Member
fetch absolute 2 from mycur
update Member set MemberPwd='654321' where current of mycur
fetch absolute 2 from mycur
delete from Member where current of mycur
select * from Member
-- 创建指向某行多列的游标,循环显示多列数据
declare mycur cursor scroll
for select MemberAccount,MemberPwd,MemberNickName from Member
open mycur
declare @acc varchar(20)
declare @pwd varchar(20)
declare @nickname varchar(20)
fetch absolute 1 from mycur into @acc,@pwd,@nickname
-- @@fetch_status:0 -- 0-提取成功,1-失败,2-不存在
while @@fetch_status=0
begin
print '用户名'+@acc+'密码:'+@pwd+'昵称'+@nickname
fetch next from mycur into @acc,@pwd,@nickname
end
11.函数
函数分为(1)系统函数,(2)自定义函数
自定义函数分为:(1)标量值函数(返回单个值),(2)表值函数()返回查询结果
(1)编写一个函数求该银行的金额总值
create function GetSumMoney() returns money
as
begin
declare @sum money
select @sum =(select sum(CardMoney) from BankCard)
return @sum
end
-- 函数调用
select dbo.GetSumMoney()
(2)传入账号编号,返回账户真实姓名
create function GetRealNameById(@accid int) returns varchar(30)
as
begin
declare @name varchar(30)
select RealName from AccountInfo where AccountId=@accid
return @name
end
select dbo.GetRealNameById(2)
-- (3)传递开始时间和结束时间,返回交易记录(存钱取钱),
-- 交易记录中包含 真实姓名,卡号,存钱金额,取钱金额,交易时间。
-- 方案一:
create function GetRecordByTime(@start varchar(30),@end varchar(30))
returns @result table
(
RealName varchar(20),-- 真实姓名
CardNo varchar(30),-- 银行卡号(与银行卡表形成主外键关系)
MoneyInBank money,-- 存钱金额
MoneyInBank money,-- 存钱金额
ExchangeTime smalldatetime -- 交易时间
)
as
begin
insert into @result
select RealName 真实姓名,CardExchange.CardNo 卡号,MoneyInBank 存钱金额,MoneyOutBank 取钱金额,ExchangeTime 交易时间
from CardExchange
inner join BankCard on CardExchange.CardNo=BankCard.CardNo
inner join AccountInfo on BankCard.AccountId=AccountInfo.AccountId
where ExchangeTime between @start + '00:00:00' and @end +'23:59:59'
return
end
select GetRecordByTime('2020-1-1','2020-12-12')
方案二(函数体内只能有return+sql查询结果):
create function GetRecordByTime(@start varchar(30),@end varchar(30))
returns table
as
return
select RealName 真实姓名,CardExchange.CardNo 卡号,MoneyInBank 存钱金额,MoneyOutBank 取钱金额,ExchangeTime 交易时间
from CardExchange
inner join BankCard on CardExchange.CardNo=BankCard.CardNo
inner join AccountInfo on BankCard.AccountId=AccountInfo.AccountId
where ExchangeTime between @start + '00:00:00' and @end +'23:59:59'
go
select GetRecordByTime('2020-1-1','2020-12-12')
*(4)查询银行卡信息,将银行卡状态1,2,3,4分别转换为汉字“正常,挂失,冻结,注销”,
-- 根据银行卡余额显示银行卡等级30万以下为“普通用户”,30万及以上为“VIP用户”,
-- 分别显示卡号,身份证,姓名,余额,用户等级,银行卡状态。
-- 用户等级函数
create function GetGrade(@cardmoney money) returns varchar(30)
as
begin
declare @result varchar(30)
if @cardmoney>=300000
set @result ='VIP用户'
else
set @result='普通用户'
return @result
end
-- 求银行卡状态函数
create function GetState(@state int)returns varchar(30)
as
begin
declare @result varchar(30)
if @state =1
set @result='正常'
else if @state=2
set @result='挂失'
else if @state=3
set @result='冻结'
else if @state=4
set @result='注销'
else
set @result='异常'
return @result
end
-- 调用查询
select CardNo卡号,AccountCode 身份证号,RealName 姓名,CardMoney 余额,
GetGrade(CardMoney)用户等级,GetState(CardState)银行卡状态
from BankCard
inner join AccountInfo on BankCard.AccountId=AccountInfo.AccountId
(5)编写函数,根据出生日期求年龄(年龄求实岁),例如:
-- 生日为2000-5-5,当前为2018-5-4,年龄为17岁
-- 生日为2000-5-5,当前为2018-5-6,年龄为18岁
create function GetAge(@birth smalldatetime) returns int
as
begin
declare @age int
set @age=year(getdate())-year(@birth)
if month(getdate())<month(@birth)
set @age=@age-1
if month(getdate())<month(@birth) and day(getdate())<day(@birth)
set @age=@age -1
end
select *,dbo.getdate(empBirth)年龄 from Emp
12.触发器
触发器分类:
(1)“Instead of”触发器-在执行操作前被执行(事前触发器)
(2)“After”触发器-在执行操作后被执行(事后触发器)
触发器中后面的案例中所需要用到的表及测试数据如下:
(1)假设有部门表和员工表,在添加员工的时候,该员工的部门编号如果在部门表中找不到,则自动添加部门信息,部门名称为“新部门”
--触发器语法:create trigger 触发器名称 on 表名 after/instead of 行为 as。。。
create trigger tri_InsertPeople on People after insert -- 事后触发器
as
if not exists(select * from Department where DepartmentId=(select DepartmrntId from inserted))
begin
insert into Department(DepartmentId,DepartmentName)
values((select DepartmentId from insterted),'新部门')
end
go
-- 测试触发器
insert into People(DepartmentId,PeopleName,PeopleSex,PeoplePhone)
values('002','赵云','男','13698547125')
insert into People(DepartmentId,PeopleName,PeopleSex,PeoplePhone)
values('006','马超','男','13698547136')
(2)触发器实现,删除一个部门的时候将部门下的员工全部删除(deleted-数据库中的储存表)
create trigger tri_DeleteDept on Department after delete
as
delete from People where DepartmentId=(select DepartmentId from deleted)
go
select * from Department
select * from People
-- 测试触发器
delete from Department where DepartmentId='006'
(3)创建一个触发器,删除一个部门的时候判断该部门下是否有员工,有则不删除,没有则删除
drop trigger tri_DeleteDept -- 创建触发器前先删除之前同名触发器
create trigger tri_DeleteDept on Department instead of delete
as
if not exists(select * from People where DepartmentId=(select DepartmentId from deleted))
delete from Department where DepartmentId =(select DepartmentId from deleted)
go
-- 测试触发器
select * from Department
select * from People
delete from Department where DepartmentId = '005'
(4)修改一个部门编号之后,将该部门下所有员工的部门编号同步进行修改(deleted、inserted数据库里的储存表)
create trigger tri_UpdateDept on Department after update
as
update People set DepartmentId=(select DepartmentId from inserted)
where DepartmentId=(select DepartmentId from deleted) -- 修改People表中的部门编号
go
update Department set DepartmentId ='005' where DepartmentId='001'
*13.存储过程
存储过程(Procedure)是SQL语句和流程控制语句的预编译集合
(1)没有输入参数,没有输出参数的存储过程
定义存储过程实现查询出账户余额最低的银行卡账户信息,显示银行卡号,姓名,账户余额
-- 方案一(不能兼顾多个并列最低):
drop proc proc_MinMoneyCard -- 删除同名存储
create proc proc_MinMoneyCard
as
select top 1 CardNo卡号,RealName 姓名,CardMoney 余额,
from BankCard
inner join AccountInfo on BankCard.AccountId=AccountInfo.AccountId
order by CardMoney
go
exec proc_MinMoneyCard
-- 方案二(余额最低,多个人并列,都可以查询):
create proc proc_MinMoneyCard
as
select top 1 CardNo卡号,RealName 姓名,CardMoney 余额,
from BankCard
inner join AccountInfo on BankCard.AccountId=AccountInfo.AccountId
where CardMoney =
(select min(CardMoney)from BankCard)
go
exec proc proc_MinMoneyCard
(2)有输入参数,没有输出参数的存储过程
-- 模拟银行卡存钱操作,传入银行卡号,存钱金额,实现存钱操作
create proc proc_Cunqian
@CardNo varchar(30),
@money money
as
update BankCard set CardMoney=CardMoney+@money where CardNo=@CardNo
insert into CardExchange(CardNo,MoneyInBank,MoneyOutBank,ExchangeTime)
values(@CardNo,@money,0,GETDATE())
go
select * from BankCard
select * from CardExchange
exec proc_Cunqian '6225547858741263',1000
(3)有输入参数,没有输出参数,但是有返回值的存储过程(返回值必须整数)
-- 模拟银行卡取钱操作,出入银行卡号,取钱金额,实现取钱操作
-- 取钱成功,返回1,取钱失败返回-1
create proc proc_Quqian
@CardNo varchar(30),
@money money
as
update BankCard set CardMoney=CardMoney-@money where CardNo=@CardNo
if @@ERROR<>0
return -1
insert into CardExchange(CardNo,MoneyInBank,MoneyOutBank,ExchangeTime)
values(@CardNo,0,@money,GETDATE())
return 1
go
declare @returnValue int
exec @returnValue =proc_Quqian '6225547858741263',2000
select @returnValue
(4)有输入参数,有输出参数的存储过程
-- 查询出某时间段的银行存款信息以及存款总金额,取款总金额
-- 传入开始时间,结束时间,显示存取款交易信息的同时,返回存款总金额,取款总金额。
create proc proc_selectExChange
@start varchar(20),-- 开始时间
@end varchar(20),-- 结束时间
@ sumIn money output, -- 存款的总金额
@sumOut money output, --取款的总金额
as
select @sumIn=(select sum(MoneyInBank) from CardExchange
where ExchangeTime between @start +'00:00:00' and @end +'23:59:59')
select @sumOut=(select sum(MoneyOutBank) from CardExchange
where ExchangeTime between @start +'00:00:00' and @end +'23:59:59')
select * from CardExchange
where ExchangeTime between @start +'00:00:00' and @end +'23:59:59'
go
declare @sumIn money
declare @sumOut money
exec proc_selectExChange '2020-1-1','2020-12-11',@sumIn output,@sumOut output
select @sumIn
select @sumOut
(5)具有同时输入输出参数的存储过程
-- 密码升级,传入卡号和密码,如果卡号密码正确,并且密码长度<8,自动升级成8位密码
-- floor(rand()*10)生成1-9随机数
create proc procPwdUpgrade
@CardNo nvarchar(20),-- 卡号
@pwd nvarchar(20) output,-- 密码,output不局限于单纯输出,可先定义值,之后再返回最终的输出值
as
if not exists(select * from BankCard where CardNo=@CardNo and CardPwd=@pwd)
set @pwd=''
else
begin
if len(@pwd)<8
begin
declare @len int=8-len(@pwd)
declare @i int =1
while @i<=@len
begin
set @pwd=@pwd+cast(floor(rand()*10)as varchar(1))
set @i=@i+1
end
update BankCard set CardPwd=@pwd where CardNo=@CardNo
end
end
go
declare @pwd nvarchar(20)='123456'
exec procPwdUpgrade '6225125478544587',@pwd output
select @pwd
实操遇到的问题(更新中):
passward nvarchar(10) collate chinese_prc_ci_as null。
collate chinese_prc_ci_as到底是什么意思呢?
collate关键字是指定SQL server的排序规则。
Chinese_PRC表示简体中文,繁体中文则为Chinese_Taiwan
CI:case-insensitive 指定不区分大小写(A 和a 被看作是一样的),如果要在查询时区分输入的大小写则改为CS
AS:Accent sensitive 指定区分重音,同样如果不需要区分重音,则改为AI
ISNULL()
实例:如果表达式为NULL,则返回指定值,否则返回表达式:
SELECT ISNULL(NULL, 'W3Schools.cn');
ISNULL(expression, value) --
参数 |
描述 |
expression |
必需。判断是否为NULL的表达式 |
value |
必需。表达式为NULL时返回的值 |
总结:重要的 SQL 命令
- SELECT - 从数据库中提取数据
- UPDATE - 更新数据库中的数据
- DELETE - 从数据库中删除数据
- INSERT INTO - 向数据库中插入新数据
- CREATE DATABASE - 创建新数据库
- ALTER DATABASE - 修改数据库
- CREATE TABLE - 创建新表
- ALTER TABLE - 变更(改变)数据库表
- DROP TABLE - 删除表
- CREATE INDEX - 创建索引(搜索键)
- DROP INDEX - 删除索引
【数据库-汇总】SQL SERVER数据库相关推荐
- 转贴 :sql数据库置疑:Sql Server数据库置疑的解决
sql数据库置疑:Sql Server数据库置疑的解决 办法 原因: 通常这个问题是由于硬盘空间不够或硬盘读写错误造成的. 现象: 数据库后面有"置疑"字样,查看系统事务日记出现以 ...
- linux 附加数据库文件,SQL Server 数据库分离与附加图文详解
SQL Server 数据库分离与附加图文教程,需要的朋友可以参考一下. 一.概述 SQL Server提供了"分离/附加"数据库."备份/还原"数据库.复制数 ...
- SQL Server 数据库之SQL Server 数据库的安全设置
SQL Server 数据库的安全设置 1. 概述 2. 更改登录用户验证方式 3. 创建与删除登录用户 4. 创建与删除数据库用户 5. 设置服务器角色权限 5.1. **查看角色属性** 5.2 ...
- 【数据库】SQL Server 数据库、附加数据库时出错。有关详细信息,请单击“消息”列中的超链接
总结一下附加数据库时出错的几点常见原因 [若有错误,欢迎指正] 原因 一.登陆方式 甲.在登录验证时,选择"Windows 身份验证",而不是"SQL Server 身份 ...
- [转载]在SQL Server数据库之间进行数据导入导出,OPENDATASOURCE
需要在c盘下先建立一个data.txt文件,然后在文件的第一行写上你要导出的列,不如说要导出id和name这两列,就在第一行写上 id,name 然后保存,使用下列SQL就可以了,你如果要保持原有的I ...
- 在SQL Server数据库之间进行数据导入导出
来源:http://kb.cnblogs.com/page/94464/ 在SQL Server数据库之间进行数据导入导出 (1).使用SELECT INTO导出数据 在SQL Server中使用最广 ...
- 如何使用Visual Studio创建SQL Server数据库项目
目录 背景 介绍 创建新的SQL Server数据库项目 发布以在SQL Server中创建新数据库 结论 背景 数据库在任何应用程序中都扮演着最重要的角色,当表.视图.存储过程的数量增加时,项目管理 ...
- SQL Server数据库学习总结及T-SQL语法使用实战
SQL Server数据库及T-SQL实战 声明 名词解释 SQL Server数据库 安装sql server 数据库中的三种完整性 SQL Server数据库基本操作 创建数据库 指定多个数据库文 ...
- VS2017操做sql server数据库
VS2017操做sql server数据库 安装sql server数据库 摸鱼怪在这里就不总结了,相信大家都会,实在不行就去问问度娘吧! 摸鱼怪在这里提醒大家,如果版本太新可能会出现不兼容问题,最开 ...
- sql的介绍——SQL Server数据库管理系统
SQL Server是微软公司推出的关系数据库管理系统,使用客户机/服务器体系结构. ,具有以下特点: 使用方便(可以图形界面操作) 可伸缩性好(做大数据库可以,也可以做小数据库) 与相关软件集成程度 ...
最新文章
- Forefront基本知识介绍
- 橡皮筋模型不太对呀?!
- mysql数据中文乱码_win10 系统解决mysql中文乱码问题
- 爬虫必须得会的Web知识
- IOS开发之Bug--遇到一个类型不确定的bug
- Stack Overflow 2021开发者调查报告 - 数据库篇!
- JVM第一讲:为什么需要 JVM?它处在什么位置?
- ASP.NET Core默认注入方式下如何注入多个实现(多种方式)
- Mybatis的动态sql(五)
- python中__new__的用法_python中的__init__ 、__new__、__call__小结及使用
- 车间调度建模系列8|扩展析取图之基于时间片段的赋时三维析取图模型
- python图像识别与提取_python图像识别与提取
- 1024程序员节节日快乐
- Unity笔记之切换鼠标图标样式、PSD格式文件导入Unity
- 如此优秀的JS轮播图,写完老师都沉默了
- python求和1到100_python实现1加到100
- EasyPlayer流媒体播放器播放HLS视频,起播速度慢的技术优化
- GoPro内存卡里的THM、LRV文件
- 领域模型的概念:失血 贫血 充血 胀血
- 关于如何免费下载专利、英文文献等?