课程地址:数据库 SQLServer 视频教程全集(99P)| 22 小时从入门到精通_哔哩哔哩_bilibili
目录
identity(主键自动增长,用户不需要为identity修饰的主键赋值)
主键通常为代理主键(无实际含义,整型数字),一般不使用有业务含义的字段充当主键
- create table student2(
- student_id int primary key,
- student_name nvarchar(200) not null
- )
-
- insert into student2 values (1,'张三')
- insert into student2 values (2,'李四')
-
- insert into student2 values (1,'张三') -- error,主键不允许重复
- insert into student2 values ('张三') -- error,主键不允许省略
- insert into student2(student_name) values ('张三') -- error,把编号student_id当主键时,必须得为它赋值
identity表示该字段的值会自动更新,不需要我们维护,通常情况下我们不可以直接给 identity 修饰的字符赋值,否则编译时会报错
语法格式为:
数据类型是整型的列才能被定义成标识列
标识列通常与 primary key 约束一起用作表的唯一行标识符
例子:
- create table student3(
- student_id int primary key identity(100,5),
- student_name nvarchar(200) not null
- )
-
- insert into student3(student_name) values ('张三') -- student_id为100
- insert into student3 values ('李四') -- OK,student_id为105
-
- select * from student3
- delete from student3 where student_name = '李四'
-
- insert into student3(student_name) values ('王五') -- student_id为110
-
- select * from student3
总结:
如果对表中数据进行了删除操作,如何让identity字段重新从某个值开始自增?
- dbcc checkident('表名', reseed, identity字段的初始值)
-
- dbcc checkident('表名', reseed, 0)
- -- 种子的值也可以是0,这样设置的话,用户插入值时,种子的初始值将从1开始
例子:
- create table emp(
- empid int identity(1,1),
- ename nvarchar(20) not null
- )
-
- insert into emp values ('aaaa')
- insert into emp values ('bbbb')
- insert into emp values ('cccc')
- insert into emp values ('dddd') -- 9行
- select * from emp
-
- delete from emp where empid = 4 -- 删除empid为4的记录
- select * from emp
-
- insert into emp values ('eeee') -- 因为执行9行时empid为4,所以执行本语句时empid为5
- select * from emp
-
- delete from emp where empid = 5
-
- dbcc checkident('emp',reseed,3) -- 20行(把emp表中identity字段的初始值重新设置为3)
-
- insert into emp values ('eeee') -- 此时插入记录时,empid为4,因为20行代码已经把empid设置成了3
- select * from emp

通常identity标记的字段,我们是不需要插入数据的,即我们不需要维护identity字段的值,它会自动更新。如果我们需要向identity修饰的字段插入值,则必须满足如下两点:
set identity_insert [database.[owner.]] {table} {on|off}
- create database Example
- use Example
-
- create table dept(
- deptid decimal(6,0) identity,
- deptname varchar(20)
- )
-
- set identity_insert Example.dbo.dept on
- -- 执行本语句的目的是:希望可以向identity修饰的字段插入值
- -- 不可以改为 set identity_insert dept on
- -- 不可以改为 set identity_insert dbo.Example.dept on
- -- 不可以改为 set identity_insert dbo.Example.dept.on
-
- insert into dept(deptid, deptname) values (1,'zhangsan')
- -- 不能改为 insert into dept values (1,'zhangsan')
-
- select * from dept
求出平均工资最高的部门的编号和部门的平均工资
top 只有 SQL Server 里才有,MySQL和Oracle里没有这种用法
- select deptno, avg(sal) "avg_sal" from emp
- group by deptno -- 临时表

写法1:
- select * from (
- select deptno, avg(sal) "avg_sal" from emp
- group by deptno -- 临时表
- ) T
- where T.avg_sal = (
- select max(E.avg_sal) from (select deptno, avg(sal) "avg_sal" from emp group by deptno) E -- 临时表
- )
写法2:创建视图
- create view v$_emp_1
- as
- select deptno, avg(sal) "avg_sal"
- from emp
- group by deptno -- 临时表
-
- select * from v$_emp_1 -- 视图可以当做一个临时表
-
- select * from v$_emp_1
- where avg_sal = (select max(avg_sal) from v$_emp_1)
方便简化查询,避免了代码的冗余,避免书写大量重复的SQL语句
- create view 视图的名字
- as
- -- select前面不能添加begin
- select语句
- -- select后面不能添加end
如隐藏emp表的工作年份和工资两列
- create view v$_emp_2
- as
- select empno, ename, job, mgr, comm, deptno
- from emp
-
- select * from v$_emp_2
- -- error
- create view v$_a
- as
- select avg(sal) from emp
-
- -- ok
- create view v$_a
- as
- select avg(sal) as "avg_sal" from emp
不使用分组,但使用了聚合函数时,默认把所有记录当做一组
悲观锁、乐观锁...
谁访问谁上锁,会导致其他用户不能访问
脏读、串行化...
事务主要用来保证数据的合理性和并发处理的能力。通俗点说:
例子:
一系列操作要么全都执行成功,要么全部执行失败,这就是事务
T-SQL使用下列语句来管理事务:
一旦事务提交或回滚,则事务结束
默认任何一个语句就是一个事务,必须显式地开启一个事务后才能提交或回滚
执行之前开启,执行之后结束(默认)
Oracle有的语句一写完就提交,有的不是;而SQL Server都是一写完就提交
判断某条语句执行是否出错:
- SET @errorSum = @errorSum + @@error
- -- @ 用户变量
- -- @@ 系统变量
每条单独的语句都是一个事务。如果成功执行,则自动提交;如果错误,则自动回滚(默认模式)
每个事务均以 begin transaction 语句显式开始,以 commit 或 rollback 语句显式结束
在前一个事务完成时,新事务隐式启动,但每个事务仍以 commit 或 rollback 语句结束
事务必须具备以下四个属性,简称ACID属性
事务是一个完整的操作。事务的各步操作是不可分的(原子的),要么都执行,要么都不执行
当事务完成时,数据必须处于一致状态,要么处于开始状态,要么处于结束状态,不允许出现中间状态
指当前的事务与其他未完成的事务是隔离的。在不同的隔离级别下,事务的读取操作,可以得到的结果是不同的
事务完成后,它对数据库的修改被永久保持,事务日志能够保持事务的永久性
- delete from dept2 where deptno = 50
- commit -- error
- rollback -- error
- create table bank(
- customerEname nvarchar(200),
- currentMoney money
- )
-
- insert into bank values ('张三',1000)
- insert into bank values ('李四',1)
-
- alter table bank add constraint check_currentMoney check(currentMoney >= 1)
-
- select * from bank

-- 张三要给李四转账1000元
-- 则张三账户余额为1000-1000=0 < 1(不符合要求)
-- 李四账户余额为1+1000=1001
-- 理应转账失败
没有事务时:
- update bank set currentMoney = currentMoney-1000 where customerEname = '张三'
- update bank set currentMoney = currentMoney+1000 where customerEname = '李四'

这显然不合理
有事务时:
- begin transaction
- declare @errorSum int
- set @errorSum = 0
- update bank set currentMoney = currentMoney-1000 where customerEname = '张三'
- set @errorSum = @errorSum + @@ERROR
- update bank set currentMoney = currentMoney+1000 where customerEname = '李四'
- set @errorSum = @errorSum + @@ERROR
- if (@errorSum<>0)
- begin
- print '转账失败'
- rollback transaction
- end
- else
- begin
- print '转账成功'
- commit transaction
- end

类似字典的目录,可以加快查询速度(视图只能简化查询,不能加快查询速度)。但若索引建立的不合理,反而会降低查询的速度
当对一个表执行增删改查操作时,会自动触发另外一些语句的执行(主要是为了完成一些约束功能)
对处理结果集分情况处理,对多行数据按单行方式做操作
数据库语言(第四代语言,命令,不需要考虑内部实现,但由于无for循环或if语句,功能弱)
TL_SQL是一个含有流程控制,只能用在SQL Server中的编程语言
字段、表、记录、属性、列、元素、约束、关系、主键、外键、check、default、unique、not null、触发器
distinct、内连接、视图...