database-notes
本文最后更新于:12 小时前
全局变量
@snum 表示全局变量
容易语法错误的地方
- update不要table关键字,直接跟表名
- insert不要table关键字,直接跟表名
- 想要切换database时,直接use其他的。比如user在mysql数据库中,直接use mysql 然后再
select host,user from user;
数据库命令
delimiter
1 |
|
启动/关闭数据库命令
1 |
|
进入数据库命令
1 |
|
创建data文件夹
创建文件夹时一定要以管理员身份打开文件夹
在C:\Program Files\MySQL\MySQL Server 5.7\bin路径下调用如下命令:
1 |
|
显示所有的仓库
1 |
|
创建数据库
1 |
|
删除数据库
1 |
|
获取仓库创建的语句
1 |
|
字符编码
1 |
|
更改数据库
1 |
|
表的命令
进入一个数据库,进行操作
1 |
|
创建表
1 |
|
查看表的结构
1 |
|
删除表
1 |
|
有限制地删除
1 |
|
- restrict表明删除表是有限制的,欲删除的基本表不能被其他表的约束所引用。如果存在依赖该表的对象,则此表不能被删除。
- cascade表明删除该表没有限制。在删除基本表的同时,相关的依赖对象一起删除。
更改表
alter + table + 表名 +add/drop + 字段名
增加字段
1 |
|
增加约束条件
1 |
|
更改字段名
1 |
|
更改字段类型
1 |
|
不能同时更改两个字段名,用逗号隔开。
删减
1 |
|
数据操作
插入数据insert
基本操作
1 |
|
插入数据之后,如何更改数据类型?
一次性插入多条数据
1 |
|
插入子查询结果
子查询不仅可以嵌套在select语句中,用以构造父查询的条件,也可以嵌套在insert语句中,用以生成要插入的批量数据。
例题:对于每一个系,求学生的平均年龄,并把结果存入数据库。
1 |
|
删除数据
delete语句的功能是,从指定表中删除满足where子句条件的所有元组。若省略where子句,则表明删除表中所有元组,但表的定义还在字典中。所以delete删除的是表中的数据,而不是表的定义。
1 |
|
更新表数据
1 |
|
更新表时不需要写table!!!!!!!!!!
查询表数据
1 |
|
SQL语句区分
- DDL data definition language 数据库定义语言 create alter drop show
- DML data manipulation language 数据操纵语言 insert update delete select
- DCL data control language GRANT 和 REVOKE
grant与revoke
基本格式
1 |
|
- all privileges:表示将所有权限授予给用户。也可指定具体的权限,如:SELECT、CREATE、DROP等。
- on:表示这些权限对哪些数据库和表生效,格式:数据库名.表名,这里写“*”表示所有数据库,所有表。如果我要指定将权限应用到test库的user表中,可以这么写:test.user
- to:将权限授予哪个用户。格式:”用户名”@”登录IP或域名”。%表示没有限制,在任何主机都可以登录。比如:”yangxin”@”192.168.0.%”,表示yangxin这个用户只能在192.168.0IP段登录
- identified by:指定用户的登录密码
- with grant option:表示允许用户将自己的权限授权给其它用户
可以使用GRANT给用户添加权限,权限会自动叠加,不会覆盖之前授予的权限,比如你先给用户添加一个SELECT权限,后来又给用户添加了一个INSERT权限,那么该用户就同时拥有了SELECT和INSERT权限。
grant使用时,可以一条语句中添加多个权限,但是只能对一张表,不能同时对多张表添加。
revoke也是这样。
刷新权限
对用户权限做了变更之后,一定记得重新加载一下权限,将权限信息从内存中写入数据库。
1 |
|
查看用户权限
1 |
|
回收权限
1 |
|
注意,回收权限之后也要flush privileges
注意
回收权限时建议加一个 cascade 级联回收。因为从某个用户回收权限时,该用户可能将权限赋予了其他用户,要一并收回。否则会拒绝执行该命令(restrict)
删除用户
1 |
|
显示字符编码
1 |
|
mysql数据类型
数据类型没有一个统一的标准,但应该符合业务项目的逻辑标准
数值类型
类型 | 大小 | 范围(有符号) | 范围(无符号) | 用途 |
---|---|---|---|---|
TINYINT | 1 byte | (-128,127) | (0,255) | 小整数值 |
SMALLINT | 2 bytes | (-32 768,32 767) | (0,65 535) | 大整数值 |
MEDIUMINT | 3 bytes | (-8 388 608,8 388 607) | (0,16 777 215) | 大整数值 |
INT或INTEGER | 4 bytes | (-2 147 483 648,2 147 483 647) | (0,4 294 967 295) | 大整数值 |
BIGINT | 8 bytes | (-9,223,372,036,854,775,808,9 223 372 036 854 775 807) | (0,18 446 744 073 709 551 615) | 极大整数值 |
FLOAT | 4 bytes | (-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38) | 0,(1.175 494 351 E-38,3.402 823 466 E+38) | 单精度 浮点数值 |
DOUBLE | 8 bytes | (-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 双精度 浮点数值 |
DECIMAL | 对DECIMAL(M,D) ,如果M>D,为M+2否则为D+2 | 依赖于M和D的值 | 依赖于M和D的值 | 小数值 |
注:若是无符号,则后面加上unsigned
整数类型注意事项
定义为tinyint类型,则数据不能超过128;但是若定义为int(6), 则数据位数可以超过6,即可以为99999999,也不报错(因为int类型上限数据宽度是11)
浮点类型注意事项
1 |
|
当输入的数据超出限定位数时,浮点数会产生精度丢失,所以不能用来存储钱。
1 |
|
为什么会产生精度丢失?
为了避免精度丢失,我们使用decimal数据类型进行存储
1 |
|
字符串与文本类型
类型 | 大小 | 用途 |
---|---|---|
CHAR | 0-255 bytes | 定长字符串 |
VARCHAR | 0-65535 bytes | 变长字符串 |
TINYBLOB | 0-255 bytes | 不超过 255 个字符的二进制字符串 |
TINYTEXT | 0-255 bytes | 短文本字符串 |
BLOB | 0-65 535 bytes | 二进制形式的长文本数据 |
TEXT | 0-65 535 bytes | 长文本数据 |
MEDIUMBLOB | 0-16 777 215 bytes | 二进制形式的中等长度文本数据 |
MEDIUMTEXT | 0-16 777 215 bytes | 中等长度文本数据 |
LONGBLOB | 0-4 294 967 295 bytes | 二进制形式的极大文本数据 |
LONGTEXT | 0-4 294 967 295 bytes | 极大文本数据 |
注:1. char()与varchar()中的数字是指字符的个数,而不是字节个数
2. 总结起来,有几点:
- 经常变化的字段用 varchar
- 知道固定长度的用 char
- 尽量用 varchar
- 超过 255 字符的只能用 varchar 或者 text
- 能用 varchar 的地方不用 text
布尔类型
1 |
|
枚举类型(单选)
只能取这几个中的一个,不能取别的
1 |
|
枚举类型的存储方式
1 |
|
好处:快,每次存取数字,存储节省空间
set类型(多选)
相当于可以插入多个数据的枚举类型
插入多个数据时,只能使用一个单引号,在一个单引号中使用逗号隔开
1 |
|
日期和时间类型
类型 | 大小 ( bytes) | 范围 | 格式 | 用途 |
---|---|---|---|---|
DATE | 3 | 1000-01-01/9999-12-31 | YYYY-MM-DD | 日期值 |
TIME | 3 | ‘-838:59:59’/‘838:59:59’ | HH:MM:SS | 时间值或持续时间 |
YEAR | 1 | 1901/2155 | YYYY | 年份值 |
DATETIME | 8 | 1000-01-01 00:00:00/9999-12-31 23:59:59 | YYYY-MM-DD HH:MM:SS | 混合日期和时间值 |
TIMESTAMP | 4 | 1970-01-01 00:00:00/2038结束时间是第 2147483647 秒,北京时间 2038-1-19 11:14:07,格林尼治时间 2038年1月19日 凌晨 03:14:07 | YYYYMMDD HHMMSS | 混合日期和时间值,时间戳 |
1 |
|
列属性完整性
主键(primary key)
唯一的,必须要有,用来标识唯一
一个表里只有一个主键,但一个主键可以由多个字段组成
一个表里的主键可能和其他表还有关系
添加主键
1 |
|
消除主键
1 |
|
组合键
两个(多个)字段做成了一个主键
作用不大
1 |
|
作用:id,昵称都是唯一的,可以用这种方法
但是,这种方法的扩展性不是太好
唯一键(unique)
可以与表里的其他字段没有关系,可以为空
一个表里可以有多个唯一键
唯一键的用处:保证数据不能重复
唯一键只在这一张表里凑热闹
添加唯一键
1 |
|
查看唯一键
1 |
|
唯一键扩展(一般不用)MUL
1 |
|
删除唯一键
1 |
|
主键不能用此方式删除!!
主键和唯一键的区别
- 主键
- 不能重复
- 不能空
- 主键可能被其他的表引用
- 唯一键
- 不能重复
- 可以为空
- 唯一键只在自己的表中折腾
SQL语句注释
1 |
|
设计数据库
- 应当有一个主键,可能用自动增长。(保证实体完整性);保证数据类型是对的;有些字段可以为空,有些字段不能为空,要有一个约束
- 考虑default的应用。比如考试学生没来,应该是默认缺考,而不是零分;或者原因未知等。
- 可能需要外部引用
外键
主表和从表之间有联系的关键字时,创建从表时要声明外键
实际开发,并发处理,禁止使用外键
外键对主表和从表的约束
- 对主表:当主表的外键在从表中被引用时,不能写(更改和删除)主表中的外键相关的字段,但是其他的字段可以写。(如学生表中的学号和食堂记录表中的学号捆绑为外键,当学号为3的学生在食堂记录表中被引用三时,不能更改学生表中学号为3学生的学号,但是可以更改其姓名)
- 对从表:不能添加主表中没有的外键数据(主表中学生编号就到5,那么从表中不能添加编号为6的学生的购买记录)
严格操作
创建表时添加外键
1 |
|
创建之后添加外键(维护时才用到)
1 |
|
删除外键
1 |
|
置空操作
主表中的绑定外键的数据被干掉了,那么从表中于其绑定为外键的关键字都置为null,但是从表中的数据保持不变。(置空是不可逆的)
级联操作
主表中被绑定的外键被干掉了,那么从表中与其相关的字段和数据都删除了,而不是置为null。比较狠
一般情况下,置空操作是留给外界删除数据的;级联操作是留给外界更新数据的。
一般都是在创建表是设置其是否有置空和级联操作
置空操作和级联操作的使用
1 |
|
数据库设计思维
关系?行?列?
关系? 关系型数据库 两张表的共有字段去确定数据的完整性
行? 一条数据 一条数据记录 实体
列? 一个字段 属性
OOP
实体和实体之间的关系
一对一
多对一
一对多
多对多
规范约束(Codd三范式)
- 确保每列的原子性:确保每一列不能再分了。(如持续时间2018-2019,这是不对的,应该再分两个字段:开始时间2018,结束时间2019)
- 在保证是第一范式的条件下,非键字段只能依赖于键字段,一张表只能描述一件事情,不能扯淡
- 保证是第二范式的基础上,消除传递依赖(如当表里有语文、数学、英语成绩时,没必要再设计一个总分栏目了,但高考成绩表这种特殊情况除外,因为有很多人都会查这个总成绩)
将一个第二范式的关系分解为多个第三范式的关系,可以在一定程度上解决原第二范式中存在的插入异常,删除异常,数据冗余度大,修改复杂等问题。
这三个都是从非主属性的角度入手。
另外的范式
BC范式
每一个决定属性因素都包含码。
多值依赖
第四范式
查询语句
sql语句的执行顺序
开始->FROM子句->WHERE子句->GROUP BY子句->HAVING子句->ORDER BY子句->SELECT子句->LIMIT子句->最终结果
sql语句的顺序
1 |
|
一个SELECT语句中,子句的顺序是固定的。例如GROUP BY子句不会位于WHERE子句的前面。熬出
执行顺序示例:
1 |
|
在上面的示例中 SQL 语句的执行顺序如下:
(1). 首先执行 FROM 子句, 从 tb_Grade 表组装数据源的数据
(2). 执行 WHERE 子句, 筛选 tb_Grade 表中所有数据不为 NULL 的数据
(3). 执行 GROUP BY 子句, 把 tb_Grade 表按 “学生姓名” 列进行分组(注:这一步开始才可以使用select中的别名,他返回的是一个游标,而不是一个表,所以在where中不可以使用select中的别名,而having却可以使用)
(4). 计算 max() 聚集函数, 按 “总成绩” 求出总成绩中最大的一些数值
(5). 执行 HAVING 子句, 筛选课程的总成绩大于 600 分的.
(7). 执行 ORDER BY 子句, 把最后的结果按 “Max 成绩” 进行排序.
单表查询
select
1 |
|
查询时可以使用列别名,可以加as也可以不加as(省略as)
escape ‘ \ ‘ 表示 \ 为转码符
1 |
|
from
1 |
|
dual
1 |
|
where
1 |
|
and的优先级高于or
where是一条一条地去查的
where子句中不能用聚集函数作为条件表达式
in
1 |
|
between…and…
1 |
|
左闭右闭
is null
1 |
|
聚合函数
1 |
|
在聚合函数遇到空值时,除了count(*) 之外,都跳过空值而只处理非空值
模糊查询
1 |
|
模糊查询时,必须使用like,不能使用=
order by 排序
1 |
|
缺省的时候,默认为升序
- asc:排序列为空值的元组最后显示
- desc:排序列为控制的元组最先显示
问题:求各个课程号及相应的选课人数,并按照选课任务降序排列
1 |
|
group查询
group by 后面跟的是查询后面的字段之一
使用group by
,查询的字段必须是分组字段和聚合函数
如要查询这张表里,男性的平均年龄和女性的平均年龄
1 |
|
在组内使用聚合函数。
注意:
- 未对查询结果分组,聚集函数将作用与整个查询结果
- 对查询结果分组后,聚集函数将分别作用于每个组,即每一组都有一个函数值。相当于细化了聚集函数的作用对象。
- 按指定的一列或多列值分组,值相等的为一组。
group_concat() 查询
1 |
|
having
两个条件语句:where having
比如,我们想查一下根据地区计算年龄平均值后,查找平均值大于24的地区,这时我们已经查出了一个虚拟的表,表里是地区和该地区的平均年龄。这时我们若再使用where age > 24
这条语句,查询的结果是原始表中age>24
的人的地区,这不是我们想要的
where
是在原本的表中去进行筛选,
having
是在查询之后的结果的表中(虚拟表),再进行筛选,此时的字段,要使用虚拟表中的字段,因此查询虚拟表的时候,最好不要使用中文名。having
后面可以直接跟原名avg(age)
,若起了别名可以跟别名,也可以跟原名。这里就凸显出来起别名的好处,所以要起一个别名。
limit
限定查找的范围
可以结合order by 使用
查找从某一名开始,连续的几名。若只给一个数字,则默认从0开始。(也就是从第一位开始查,和C语言中数组的第一个元素下标为0相对应)
1 |
|
两个参数的limit
LIMIT 子句可以被用于强制 SELECT 语句返回指定的记录数。LIMIT 接受一个或两个数字参数。参数必须是一个整数常量。
如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目。初始记录行的偏移量是 0(而不是 1): 为了与 PostgreSQL 兼容,MySQL 也支持句法: LIMIT # OFFSET #。
1 |
|
这些都是常用的条件限制语句:where,having,limit
distinct
去重,在筛选的结果中去掉重复的
显示这张表里所有出现的城市,但是不能出现两个上海,即不能重复
查谁之前写一个distinct
代表去重
查询该表中不同的地址有多少个:
1 |
|
默认情况下其实是all
,只不过一般默认情况都忽略了
union取并集
联合查询只要求字段一样,对应项的数据类型也必须相同
将两个表查询的数据联合显示
1 |
|
union 自动去重
union all 保留所有
intersect 取交集
1 |
|
except取差集
1 |
|
多表查询
left join right join inner join 都要用on 不能用where
inner join(内连接)
两张表使用相同的公共字段进行联合查询
两表联合查询,如Student表中存储了学生的信息,表中的id为学生的学号;表score中存储了学生的成绩信息,该表中的id为score表中的编号,而stuid才是学生的学号,所以使用如下语句对名字和成绩进行联合查询
1 |
|
让公共字段相等
注意:
id和stuid前面必须要加是哪一张表,不能省去
若有三张表,则后面继续加inner join
1
2
3
4select name,score
from student
inner join score on student.id=score.stuid
inner join ...
注意
给表起别名的时候,不能加引号
left join
左连接,以左表为基准 以左排头为基准,向左看齐
就是把inner join换成left join
左表:from
后面的第一张表,就是左表,(也是left join左边的那张表)以它为基准,即使辅表中没有相关的数据,也要将左表中要查询的信息给出来
1 |
|
所以inner join以项较少的那一个为基准
right join
以右排头为基准,向右看齐
以right join右边的表为基准
1 |
|
内连接和向左看齐 比较实用
cross join
交叉连接 ,返回两表的笛卡尔积 和省略cross join返回的结果是一样的,都是笛卡尔积
1 |
|
1 |
|
逗号,就相当于交叉连接?也不一定好像
natural join
自然连接? 自然内连接
类似于内连接,但是同时查询两个表的公共字段,保证两张表中公共的字段名一模一样,如两张表中都叫id 根据同名字段来判断的
1 |
|
只是简单地合起来
在等值连接中,把目标列中重复的属性列去掉则为自然连接
注意:
若查询的两表中没有相同的字段名称,则返回两表的笛卡尔积
若查询的两表中有多个相同的字段名称,则返回空
using
当连接的表有多个字段相同时,用来指定连接的字段(唯一的字段)。两张表字段都是一样的,指定谁来作为连接字段
此时处理方式和natural相同 只不过由于有多个相同字段,所以不能使用natural来处理
其实就是,两个表连接时,完全相同的字段只保留一个
还会有自然左连接和自然右连接,分别向左看齐,向右看齐
在实际使用时,一般都写全,很少用自然连接,using,这样可读性也不好
写全:谁=谁 score.stuid=student.id
自身连接
连接操作不仅可以在两个表之间进行,也可以是一个表与其自身进行连接。
自身连接时,给要查询的那个表命两个不同的名字(在from中,因为select语句会先执行from)
例题:查询每一门课程的间接先修课(先修课的先修课)
1 |
|
子查询
in¬ in
内层的查询只查询出外层需要的字段
先给一个子查询的实例
查score表中成绩大于等于80分的学生的信息(储存在student表中)
1 |
|
括号里的查询只能返回一个字段stuid,而不能是*,否则对不上,因为我们只需要根据分数大于80的学生的学号,而不需要其他的信息(如成绩,考试编号等)
若返回值(stuId)不止一个,则要使用in
,若返回值只有一个,则可以使用=
一般情况下都使用in
有in
就有not in
子查询可以用连接运算替代
有的子查询可以用连接运算替代,而有的不可以。下面给出一个子查询可以由连接运算替代的例子:
例题:查询选修了课程名为“信息系统”的学生的学号和姓名。
1 |
|
这是嵌套查询的版本,用连接运算替代如下:
1 |
|
子查询的执行顺序
一般先执行子查询,再执行父查询,但是相关子查询例外。相关子查询,先执行父查询,再执行子查询。
相关子查询的例题: 找出每个学生超过他选修课程平均成绩的课程号。
1 |
|
执行相关子查询时,不能像求解不相关子查询那样,一次将子查询求解出来,然后求解父查询。内层查询由于与外层查询有关,因此必须反复求值。每次从外层查询中取出sc的一个元组x,将元组x的sno值传送给内层查询,然后执行内层查询,得到值之后,用该值替代内层查询,得到外层查询。执行这个外查询,得到一部分结果。然后外层查询取出下一个元组重复做上述步骤处理,直到外层的sc元组全部处理完毕。
注意
- 子查询不能使用order by子句,order by子句只能对最终查询结果排序。但子查询可以使用group by子句
- 层层嵌套方式反映了sql语言的结构化
- 有些嵌套查询可以用连接运算替代
exists¬ exists
放在where后面,格式如下
1 |
|
如果子查询有任意数据返回,exists就返回true,子查询外的查询语句执行
如果子查询没有数据返回,exists就返回false,子查询外的查询语句就不执行
若查出括号里有值,则进行括号外面的查找操作
比如,这个班里有一个人考了一百分,则这个班里每个人都发一个红包(扯淡需求)
1 |
|
in与exists的区别
我们以A、B表为例,两表通过 id 字段进行关联。
1、当 B 表的数据集小于 A 表时,用 in 优化 exist;使用 in ,两表执行顺序是先查 B 表,再查 A 表
1 |
|
2、当 A 表的数据集小于 B 表时,用 exist 优化 in;使用 exists,两表执行顺序是先查 A 表,再查 B 表
1 |
|
简单一句话:in后面放数据量小的表,exits后面放数据量大的表
这就是小表驱动大表,即小的数据集驱动大的数据集的思想。
高级部分
视图
作用:
- 防止用户看到敏感数据(比如某人在银行账户上存了多少钱)
- 有意地隐藏表的结构
- 降低了sql的复杂度
视图和函数有类似的意思,但是它不是函数
视图是从一个或几个基本表(或视图)导出的表,他与基本表不同,是一个虚表,数据库中只存放视图的定义,不存放视图对应的数据,这些数据仍然存放在原来的基本表中。所以基本表中的数据发生变化,从视图中查询出来的数据也就随之改变了。
对视图的更新操作可能会受到限制:增,删,改
创建视图
1 |
|
后面的select语句不允许有distinct和order by子句,因为它没有数据
执行create view 时只是把视图定义存入数据字典,并不执行其中的select语句;只是在对视图查询时,才按视图的定义从基本表中将数据查出。
最后可以加上
with check option
WITH CHECK OPTION:透过视图进行增删改操作时,不得破坏视图定义中的谓词条件(即子查询中的条件表达式)
例题:建立信息系学生的视图,并且进行修改和插入操作时仍需保证该视图只有信息系的学生。1
2create view ISstudent as
select sno,sname,sage from s where sdept='IS' with check option;
行列子集视图
若一个视图是从单个基本表导出的,并且只是去掉了基本表的某些列和某些行,但保留了主码,我们称这类视图为行列子集视图。ISstudent视图就是一个行列子集视图。
带表达式的视图
就是带虚拟列的视图。
定义视图时可以根据应用的需要,设置一些派生属性列。这些派生属性由于在基本表中不实际存在也称他们为虚拟列。带虚拟列的视图也称为带表达式的视图。
例题:定义一个反映学生出生年份的视图
1 |
|
分组视图
用带有聚集函数和group by 子句的查询来定义视图。
例题:将学生的学号和他的平均成绩定义成一个视图
1 |
|
使用视图
1 |
|
在可视化窗口中,创建视图后,直接双击视图就可以查询,这和select * from vw_stu
是等价的
视图消解
RDBMS执行对视图地查询时,首先进行有效性检查。检查查询中涉及的表、视图等是否存在。如果存在,则从数据字典中取出视图的定义,把定义中的子查询和用户的子查询结合起来,转换成等价的对基本表的查询,然后再执行修正了的查询。这一转换过程称为视图消解。
显示视图
在终端中显示当前视图
1 |
|
默认显示视图
所以如果要区分table和view的话,view前面一定要加上前缀vw
还可以使用如下语句:
1 |
|
还有一种赋予b格的显示方式
1 |
|
更改视图
把create
改成alter
,后面跟create的语句一样,赋给它新的功能即可。
更新视图
更新视图本质上就是更新表。一般只有行列子集视图可以被更新。
删除视图
把create
改成drop
,删去as
及其后面的语句即可
注意,基本表删除后,由该基本表导出的所有视图(定义)没有被删除,但均已经无法使用了。删除这些视图(定义)需要显式地使用drop view语句。
视图的两种算法
有两种算法:MERGE, TEMPTABLE
把子查询用到视图里,发现结果和想象的不一样??与视图算法有关
1 |
|
此时要设置一个temptable
的视图算法
在创建视图时设计视图算法
1 |
|
触发器
- 触发器(Trigger)是用户定义在关系表上的一类由事件驱动的特殊过程
- 由服务器自动激活
- 可以进行更为复杂的检查和操作,具有更精细和更强大的数据控制能力
定义触发器
1 |
|
1 <触发器名>
触发器的名称,触发器在当前数据库中必须具有唯一性。如果要在某个特定数据库中创建,名称前面应该加上数据库的名称. 如 xxx_trigger_xxx 命名
2 <触发时机> BEFORE | AFTER
触发时机 BEFORE 和 AFTER,触发器被触发的时刻,表示触发器是在激活它的语句之前或之后触发。若希望验证新数据是否满足条件,则使用 BEFORE 选项;若希望在激活触发器的语句执行之后完成几个或更多的改变,则通常使用 AFTER 选项。
3 <触发事件> INSERT | UPDATE | DELETE
触发事件,用于指定激活触发器的语句的种类。
注意:三种触发器的执行时间如下。
触发器类型 触发器功能 激活触发器的语句
INSERT触发器 将新行插入表时激活触发器。 INSERT ,LOAD, DATA ,REPLACE
DELETE触发器 从表中删除某一行数据时激活触发器。 DELETE ,REPLACE
UPDATE触发器 更改表中某一行数据时激活触发器。 DELETE
4 <表名>
与触发器相关联的表名,此表必须是永久性表,不能将触发器与临时表或视图关联起来。在该表上触发事件发生时才会激活触发器。同一个表不能拥有两个具有相同触发时刻和事件的触发器。例如,对于一张数据表,不能同时有两个 BEFORE UPDATE 触发器,但可以有一个 BEFORE UPDATE 触发器和一个 BEFORE INSERT 触发器,或一个 BEFORE UPDATE 触发器和一个 AFTER UPDATE 触发器
5 <关键字 FOR EACH ROW>
一般是指行级触发,对于受触发事件影响的每一行都要激活触发器的动作。例如,使用 INSERT 语句向某个表中插入多行数据时,触发器会对每一行数据的插入都执行相应的触发器动作。
6 <触发器主体>
触发器动作主体,包含触发器激活时将要执行的 MySQL 语句。如果要执行多个语句,可使用 BEGIN…END 复合语句结构。
注意:每个表都支持 INSERT、UPDATE 和 DELETE 的 BEFORE 与 AFTER,因此每个表最多支持 6 个触发器。每个表的每个事件每次只允许有一个触发器。单一触发器不能与多个事件或多个表关联。
NEW和OLD的使用:
触发器类型 | NEW和OLD的使用: |
---|---|
INSERT触发器 | NEW表示将要或者已经新增的数据。 |
DELETE触发器 | OLD用来表示将要或者已经被删除的语句。NEW表示将要或者已经被修改的语句 |
UPDATE触发器 | OLD表示将要或者已经被删除的数据。 |
注意
- 不能在触发器中使用开始或结束事务的语句。
- MySQL的触发器是按照BEFORE触发器、行操作、AFTER触发器的顺序执行的,其中任何一步发生错误都不会继续执行剩下的操作,如果对事务表进行的操作,如果出现错误,那么将会被回滚,如果是对非事务表进行操作,那么就无法回滚了,数据可能会出错。
定义触发器的语法说明
- 创建者:表的拥有者
- 触发器名
- 表名:触发器的目标表
- 触发事件:INSERT、DELETE、UPDATE
- 触发器类型
行级触发器(FOR EACH ROW)
语句级触发器(FOR EACH STATEMENT)
1 |
|
在TEACHER表上创建了一个AFTER UPDATE触发器。如果表TEACHER有1000行,执行如下语句:
UPDATE TEACHER SET Deptno=5;
如果该触发器为语句级触发器,那么执行完该语句后,触发动作只发生一次
如果是行级触发器,触发动作将执行1000次
1 |
|
触发器删除
触发器必须是一个已经创建的触发器,并且只能由具有相应权限的用户删除。
1 |
|
1 |
|
事务
操作比较严谨的,跟钱打交道的
点立即购买,没付款,钱去哪了?
转账,最后再提醒一次,是不是这个卡号,点了确定,才把钱转出去
难道每一次买东西都给阿里增加一条数据吗?你买一个东西,马上给人家增加50块钱?再退款,再update?
总有一个步骤,确定一定以及肯定之后,才能更新这个数据,我们管它叫做事务,transaction
开启事务
1 |
|
只要你commit
,就不能再rollback
从事务开始的时候,随时随地可以rollback
,但是一但commit
,就不能再rollback
了。最好的例子就是,淘宝发货,你付款,收货。
所以在公司里,一般遇到金额转账,跟钱有关的,一般都用transaction
rollback to
设置回滚点,使用savepoint操作
1 |
|
事务的四个特性ACID
- atomicity 原子性 不能再分了,事务是一个整体,要死一起死,要活一起活
- consistency 一致性 事务一但commit,数据也一定要达到一致的状态,所有的数据都应该是正常的
- isolation 隔离性 所有的事务都是相互隔离的
- durability 持久性 事务一但commit,就不能再更改了,在数据库中永久的写存
注意:必须保证引擎是innodb,才能使用事务
索引(index)
优点:查询速度快
缺点:
- 一旦设置索引,数据的增删改,效率都会变低,而且变得不是一般的低。
- 索引还占空间
所以有些东西设置成索引,有些东西强制不能设置成索引,有些大公司明确要求
四种类型
- 主键索引:primary key
- 唯一键索引:
- 普通索引
- 全文索引:搜索引擎使用,mysql不支持中文的全局索引,但是可以使用sphinx
设置索引
添加表时设置 不常用
创建一个普通索引 常用
1 |
|
设置一个唯一索引
随便设的
1 |
|
可以为多个列创建索引
不说的话,默认是按照升序排列(前两个)
设置一个主键索引
1 |
|
修改索引
1 |
|
删除索引
1 |
|
为什么要创建索引?
- 经常要查这一列,比如高考总分
- 共用字段,可能创建索引
注意:
- 表里数据非常少,千万不要创建索引 神经病行为
- 还有性别,这种,种类很少,不要创建索引
聚簇索引
1 |
|
在Student表的Sname列上建立一个聚簇索引
- 在最经常查询的列上建立聚簇索引以提高查询效率
- 一个基本表上最多只能建立一个聚簇索引。
- 经常更新的列不宜建立聚簇索引
问题:
索引怎么用???
存储过程
一般开发用不到
Introduction
用来模块化设计 DBA用的
可以用来增删改查,可以支持事务,相当于sql里的函数
给一个案例,双十一了,淘宝想把所有人的账户都给发一个红包,把所有人的头像都改了,这操作用视图肯定不行,因为视图只能查,明显用存储过程。这个存储过程,双十一之前DBA先写好,然后回家睡觉。双十一了,马云打电话说,赶紧发红包,改头像23:59,打开笔记本,执行存储过程,他就会默认执行之前设置过的sql
,就不用再一点一点去写了,就相当于调用一个函数一样。
在mysql
中,每一个;
就相当于一个语句,执行完直接发送服务器了,有点类似matlab
中的命令行。但是执行下述语句之后
1 |
|
分号此时没用了,只有使用//
才能把语句发出去,去执行它
用完存储过程之后,再进行还原也可以
1 |
|
存储过程里肯定有多个sql语句,之间用;
隔开
在存储过程中,最好使用transaction,这样比较符合常规
建立存储过程
1 |
|
调用存储过程
1 |
|
删除存储过程
1 |
|
查看存储过程
1 |
|
显示数据库里的所有存储过程
1 |
|
有趣的函数
number
rand()
生成一个随机数
1 |
|
抽奖
1 |
|
向上取整
1 |
|
四舍五入
1 |
|
向下取整
1 |
|
截取数字
1 |
|
随机排序
1 |
|
string
转换成大写
1 |
|
转换成小写
1 |
|
截取字符串
1 |
|
拼接字符串
1 |
|
补充:concat的有趣用法
1 |
|
数据库角色
数据库角色是被命名的一组与数据库操作相关的权限,角色是权限的集合。因此,可以为一组具有相同权限的用户创建一个角色,使用角色来管理数据库权限可以简化授权的过程。
1 |
|
问题
使用sql脚本文件写入数据时,出现command /2 错误的原因:
文件的路径只能用正斜杠/,不能用反斜杠\。
ERROR 1406 (22001): Data too long for column ‘Ssex’ at row 1
更改命令行的编码格式 从gbk到utf8
1
chcp 65001