第一章 了解 SQL
介绍几个数据库的概念
- 数据库(database) 通过DBMS创建和操纵的保存有组织的数据的容器(通常是一个文件或一组文件)。
- 数据库软件/数据库管理系统(DBMS)访问数据库,创建和操纵数据库,比如 MySQL、Oracle
- 表(table) 某种特定类型数据的结构化清单。
- 列(column) 表中的一个字段。所有表都是由一个或多个列组成的。
- 数据类型(datatype) 所容许的数据的类型。每个表列都有相应的数据类型,它限制(或容许)该列中存储的数据。
- 行(row) 表中的一个记录。
- 主键(primary key)一列(或一组列),其值能够唯一区分表中每个行。
- 任意两行都不具有相同的主键值
- 每个行都必须具有一个主键值(主键列不允许NULL值)
- 不在主键列中使用可能会更改的值。
- 不更新主键列中的值
- 不重用主键列的值
- SQL(Structured Query Language)结构化查询语言
SQL语言分类
- DDL (data definition language):CREATE TABLE;ALERT TABLE;DROP TABLE;CREATE INDEX;DROP INDEX。数据定义语言,负责数据的模式定义与数据的物理存取构建
- DML(data manipulation language):INSERT;UPDATE;DELETE。数据操作语言,用于改变数据库的数据
- DQL(data query language):SELECT。 数据查询语言,主要用来查询数据库中的数据
- DCL(data control language):ALERT PASSWORD;GRANT;REVOKE;CREATE SYNONM。数据控制语言,用于设置数据库用户的各种操作权限
第二章 MySQL简介
DBMS可分为两类
- 基于共享文件系统的DBMS:Microsoft Access、FileMaker,用于桌面用途,通常不用于高端或更关键的应用。
- 基于客户机—服务器的DBMS
- 服务器部分是负责所有数据访问和处理的一个软件。这个软件运行在称为数据库服务器的计算机上
- 客户机是与用户打交道的软件
MySQL版本
- 4 InnoDB引擎,增加事务处理、并改进全文本搜索等的支持。
- 4.1 对函数库、子查询、集成帮助等的重要增加。
- 5 存储过程、触发器、游标、视图等
MySQL工具
- mysql命令行实用程序,它是核心 MySQL 安装的一部分
mysql -u 登录名 -p 端口号 -h 主机名 -P 密码 # 默认的可以省略
- MySQL Administrator 图形交互客户机,下载地址 http://dev.mysql.com/
- MySQL Query Browser 下载地址 http://dev.mysql.com/downloads/
第三章 使用MySQL
选择数据库
USE 数据库名称
了解数据库和表
SHOW DATABASES # 返回可用数据库的一个列表
SHOW TABLES # 返回当前选择的数据库内可用表的列表
SHOW COLUMNS FROM 表名 # 显示指定表的所有列信息
第四章 检索数据
SQL语句不区分大小写,可以对关键字使用大写,对表名和列使用小写
- SELECT:检索
- DISTINCT 去重
- LIMIT 3,4 限制数量,从行 3 开始检索出不少于 4 行。注意:行计数是从 0 开始的
- LIMIT 4 OFFSET 3 和上面的一样,从行 3 开始检索出不少于 4 行
SELECT * FROM admin_user LIMIT 2 OFFSET 1
第五章 排序检索数据
ORDER BY :A 被视为与 a 相同
- ASC 默认升序
- DESC 可以指定降序
-- LIMIT 与 ORDER BY 语句顺序不能改变
SELECT * FROM admin_user ORDER BY username LIMIT 1
比较 NULL < ' '(空格) 总是在 '' (空字符串)前 < 数字 < 中文
SELECT * FROM admin_user ORDER BY email asc
第六章 过滤数据
- WHERE
- != 不等于
- <> 不等于
- BETWEEN
- 单引号与双引号都可以用来限定字符串,如果是与 值 比较引号可以省略
- NULL 它与字段包含0、空字符串或仅仅包含空格不同
1简单使用
SELECT * FROM admin_user WHERE username = 'ADMIN' ORDER BY username LIMIT 2
2 使用以下语句期望可以将为 NULL 的值查出来,但实际不可以
SELECT * FROM admin_user WHERE gender != 0
3 使用 NULL 时需要注意,它只能使用 IS / IS NOT 来过滤
SELECT * FROM admin_user WHERE IFNULL(gender,0) = 0
SELECT * FROM admin_user WHERE IFNULL(gender,0) != 1
4 注意空格,= ‘’ 或者 = ‘ ’ 可以匹配带空格或不带空格的非 NULL 值
第七章 数据过滤
- ADN
- OR
- IN
- NOT MySQL 支 持 使 用 NOT 对 IN 、 BETWEEN 和 EXISTS 子句取反
1 AND 比 OR 的优先级高
SELECT * FROM admin_user WHERE username = 'admin' or username = 'string' and gender = 0
以上语句实际为
SELECT * FROM admin_user WHERE username = 'admin' or ( username = 'string' and gender = 0 )
2 IN操作符一般比OR操作符清单执行更快
第八章 用通配符进行过滤
LIKE ,LIKE 'admin' 可以匹配到等于 ‘admin’ 的记录
- % 任何字符出现任意次数
- _ 只匹配单个字符而不是多个字符
1 不区分大小写
SELECT * FROM admin_user WHERE username LIKE 'ad%'
2 注意尾空格 LIKE ‘%min’ 不能匹配末尾有空格的 `admin `
3 注意 NULL,LIKE '%' 不能匹配 NULL
SELECT * FROM admin_user WHERE email LIKE '%'
注意:
- 不要过度使用通配符,效率较低
- 尽量放到搜索模式的最后
- 放错地方可能与预期不符
第九章 用正则表达式进行搜索
REGEXP 与 LIKE '%内容%' 一样。不区分大小写,可以使用 REGEXP BINARY 'JetPack .000' 区别大小写
- . 一个点,匹配任意一个字符
- | 相当于 OR ,REGEXP 'AD|BC'
- [123] 匹配几个字符之一,与 [1|2|3] 写法一致。REGEXP '[123]A' 可以匹配:‘1AB’,‘2AC’ 等,不能匹配 ‘AB’
- ^ 非,[^123] 匹配除这些字符外的任何东西,这些表示 123,23,12
- - 匹配范围 [1-3] [a-z] [A-Z] 这个时候区分大小写
- \\ 双反斜杠用来匹配特殊字符,REGEXP '\\.' 匹配有一个点的记录。使用两个是因为 MySQL 自己解释一个、正则表达式库解释一个
- \\\ 匹配反斜杠本身
- 匹配字符类
- 匹配多个实例
- 定位符
1 与 LIKE '%内容%' 一样
SELECT * FROM admin_user WHERE username REGEXP 'adm'
2 字符类
3 匹配多个实例
SELECT * FROM admin_user WHERE username REGEXP '[[:alnum:]]{7}' -- 可以匹配不少于 7 个的字符串
4 定位符
^ 的双重用途:在集合中(用[和]定义),用它来否定该集合,否则,用来指串的开始处。
SELECT * FROM admin_user WHERE username REGEXP '^string' -- 匹配 string 开头的
5 使用如下语句返回 0 或 1 验证是否匹配
SELECT 'hello' REGEXP 'hello'
第十章 创建计算字段
- Concat() 函数:拼接字段 SELECT CONCAT(1,2,3) 可以传入多个参数。注意:多数DBMS使用+或||来实现拼接
- RTrim() 函数:去掉右边的空格
- LTrim() 函数:去掉左边的空格
- Trim() 函数:去掉左右两边的空格
- AS:使用别名
- 使用算术运算
第十一章 使用数据处理函数
函数没有SQL的可移植性强,不赞成使用特殊实现的功能
1. 常用文本处理函数
TRIM() 去掉空格
SELECT TRIM(' abc ') -- abc
LEFT() 返回串左边的几个字符串,小于 0.5 时为空,进行四舍五入
SELECT LEFT("abc",2) -- ab
SELECT LEFT(1234,-1) -- 返回空字符串
SELECT LEFT(1234,1.5) -- 12
SELECT LEFT(1234,1.4) -- 1
RIGHT() 返回串右边的几个字符,小于 0.5 时为空,进行四舍五入
SELECT RIGHT('123',1) -- 3
SELECT RIGHT('123',0) -- 空字符串
LOCATE() 是否匹配
SELECT LOCATE(username,'admin'),username FROM admin_user
LOWER() 转为小写
SELECT LOWER('ACd') -- acd
UPPER() 转为大写
SELECT UPPER('abc') -- ABC
SOUNDEX() 返回 SOUNDEX 值,一种语音算法
SELECT SOUNDEX("abc") -- A120
SUBSTR() 返回子字符串,从 1 开始
SELECT SUBSTR(123 FROM 1 FOR 4) -- 123
SELECT SUBSTR(123 FROM 0 FOR 4) -- 空
2. 日期和时间处理函数
SELECT NOW(); -- 2020-03-23 08:28:05
SELECT CURRENT_DATE; -- 2020-03-23
SELECT CURRENT_TIME; -- 08:26:54
SELECT DATE(NOW()); -- 2020-03-23
SELECT YEAR(NOW()); -- 2020
SELECT MONTH(NOW()); -- 3 当前是 2020-03-23
SELECT DAY(NOW()); -- 23
SELECT HOUR('2020-01-05 00:00:01'); -- 0
SELECT MINUTE('2020-01-05 00:0:01'); -- 0
SELECT SECOND('2020-01-05 00:00:01'); -- 1
SELECT DAYOFWEEK(NOW()) -- 2 当前是周一,周日是 1
-- 日期运算,两者可接受参数较多:SECOND MINUTE HOUR DAY WEEK MONTH YEAR 等
SELECT ADDDATE(NOW(),INTERVAL 1 YEAR);
SELECT DATE_ADD(NOW(),INTERVAL 1 YEAR);
-- 当前时间加几秒
SELECT ADDTIME('2020-01-05 00:00:01',6) -- 2020-01-05 00:00:07
-- 日期差
SELECT DATEDIFF('2020-01-05','2020-01-06'); -- -1 前面减后面的
3. 数值处理函数
第十二章 汇总数据
- AVG 忽略列值为NULL的行
- COUNT
- 使用COUNT(*)对表中行的数目进行计数, 不管表列中包含的是空值( NULL)还是非空值
- 使用COUNT(column)对特定列中具有值的行进行计数,忽略 NULL 值
SELECT COUNT(gender) FROM admin_user -- 只计算不为 null 的行数
- MAX 忽略列值为NULL的行,一般用于日期和数值列。用于文本,返回第一行
- MIN 忽略列值为NULL的行,一般用于日期和数值列。用于文本,返回最后一行
- SUM 忽略列值为NULL的行
- ALL/DISTINCT 以上 5 个函数针对的列默认为 ALL,也可以使用 DISTINCT ,只对去重后的数据进行计算
第十三章 分组数据
- GROUP BY:
- 如果分组列中具有NULL值,则NULL将作为一个分组返回。如果列中有多行NULL值,它们将分为一组
- 必须出现在 WHERE 子句之后, ORDER BY 子句之前
- GROUP BY子句中每个列都必须是检索列或有效的表达式(但不能是聚集函数)
- 如果在SELECT中使用表达式,则必须在GROUP BY子句中指定相同的表达式。不能使用别名
- HAVING:WHERE过滤行,而HAVING过滤分组,HAVING支持所有WHERE操作符
WITH ROLLUP 计算汇总和
SELECT username,COUNT(*) FROM admin_user GROUP BY username WITH ROLLUP
ORDER BY 可以对分组后的别名进行排序
SELECT gender,AVG(gender) FROM admin_user GROUP BY gender ORDER BY gender DESC
select 子句顺序
第十四章 使用子查询
- 在WHERE子句中使用子查询(如这里所示),应该保证SELECT语句具有与WHERE子句中相同数目的列。通常,子查询将返回单个列并且与单个列匹配,但如果需要也可以使用多个列。
- 虽然子查询一般与IN操作符结合使用,但也可以用于等于(=)、不等于(<>)等其它比较运算符
第十五章 联结表
SELECT * FROM admin_user, admin_role
- 等值联结/内部联结 与 INNER JOIN 用法一致,都是内联结区别于 left/right join 的外联结。
- 没有联结条件的表关系返回的结果为笛卡儿积。如果其中一个表的数量为 0 ,那总数就是 0
- MySQL在运行时关联指定的每个表以处理联结。这种处理可能是非常耗费资源的,因此应该仔细,不要联结不必要的表。联结的表越多,性能下降越厉害。
第十六章 创建高级联结
- 自联结:(两个相同的表进行关联)用自联结而不用子查询,自联结通常作为外部语句用来替代从相同表中检索数据时使用的子查询语句。虽然最终的结果是相同的,但有时候处理联结远比处理子查询快得多。应该试一下两种方法,以确定哪一种的性能更好
- 自然联结 排除多次出现,使每个列只返回一次
- 外部联结(LEFT/RIGHT OUTER JOIN)
第十七章 组合查询
SELECT user_id , username FROM admin_user
UNION
SELECT user_id , username FROM admin_user
ORDER BY user_id
如果以上语句的列顺序或列名不一致,将出现一个笛卡尔乘积的结果;
只能使用一条ORDER BY子句,它必须出现在最后一条SELECT语句之后。对于结果集,不存在用一种方式排序一部分,而又用另一种方式排序另一部分的情况,因此不允许使用多条ORDER BY子句。
并( UNION) 或复合查询(compound query),使用场景
- 在单个查询中从不同的表返回类似结构的数据
- 对单个表执行多个查询,按单个查询返回数据
注意事项:
- UNION 必须由两条或两条以上的 SELECT 语句组成,语句之间用关键字UNION分隔
- UNION 中的每个查询必须包含相同的列、表达式或聚集函数
- 列数据类型必须兼容:类型不必完全相同,但必须是DBMS可以隐含地转换的类型(例如,不同的数值类型或不同的日期类型)。
UNION ALL 不会对结果进行去重,它完成 WHERE 子句完成不了的工作,比如查询两条一样的数据?
第十八章 全文本搜索
并非所有引擎都支持全文本搜索。两个最常使用的引擎为MyISAM和InnoDB,前者支持全文本搜索,而后者不支持。
启用全文本搜索支持 FULLTEXT、ENGINE = MYISAM ,FULLTEXT可以索引多个列
- 可以在创建表时指定FULLTEXT,或者在稍后指定(在这种情况下所有已有数据必须立即索引)。
- 不要在导入数据时使用FULLTEXT,更新索引增加开销,应该导入完毕再修改表,定义 FULLTEXT。这样不仅可以快速导入数据,还可以一次性完成索引,缩短时间。
CREATE TABLE productnotes (
note_id INT NOT NULL AUTO_INCREMENT,
prod_id CHAR ( 10 ) NOT NULL,
note_date datetime NOT NULL,
note_text text NULL,
PRIMARY KEY ( note_id ),
FULLTEXT ( note_text )
) ENGINE = MYISAM
进行全文本搜索,Match() 指定被搜索的列, Against() 指定要使用的搜索表达式
- 传 递 给 Match() 的 值 必 须 与FULLTEXT()定义中的相同。如果指定多个列,则必须列出它们(而且次序正确)。
- 搜索不区分大小写 除非使用BINARY方式
- 自动排序,等级高的在前。like 需要与 order by 配合
- 排序多个搜索项,果指定多个搜索项,则包含多数匹配词的那些行将具有比包含较少词(或仅有一个匹配)的那些行高的等级值
SELECT note_text FROM productnotes
WHERE match ( note_text ) against ( 'food' )
-- 与 like '%food%' 作用相同
什么是等级?
Match()和Against()的结果是具有等级的,等级由MySQL根据行中词的数目、唯一词的数目、整个索引中词的总数以及包含该词的行的数目计算出来
SELECT note_text, match ( note_text ) against ( 'food' ) as rank
FROM productnotes
使用查询扩展
- 返回多行,第一行包含词anvils,因此等级最高。第二行与anvils无关,但因为它包含第一行中的两个词,所以也被检索出来。
- 行越多越好 表中的行越多(这些行中的文本就越多),使用查询扩展返回的结果越好
SELECT note_text FROM productnotes
WHERE MATCH ( note_text ) AGAINST ( 'anvils' WITH QUERY EXPANSION)
布尔文本搜索
- 仍然匹配词food,但-rope*明确地指示MySQL排除包含rope*(任何以rope开始的词,包括ropes)的行
- 排列而不排序,在布尔方式中,不按等级值降序排序返回行
SELECT note_text FROM productnotes
WHERE MATCH ( note_text ) AGAINST ( 'food -ROP*' IN BOOLEAN MODE)
第十九章 插入数据
1. 插入完整的行
不安全的插入,高度依赖于表中列的定义次序
INSERT INTO productnotes VALUES ( NULL, 'a1', NOW( ), 'hello ' )
安全但是繁琐,给出了列名,并且省略了不需要的列
- 该列定义为允许NULL值(无值或空值)
- 在表定义中给出默认值
INSERT INTO productnotes(note_id,prod_id,note_date)
VALUES ( NULL, 'a1', NOW( ) )
使用 LOW_PRIORITY 指示 MySQL 降低 INSERT 语句的优先级,先执行 SELECT,提高性能。同样适用于 UPDATE/DELETE
INSERT LOW_PRIORITY INTO productnotes(prod_id,note_date,note_text)
VALUES ('a2', NOW( ), 'hello ' )
2. 插入多个行
多个 insert 语句使用封号隔开
INSERT LOW_PRIORITY INTO productnotes(prod_id,note_date,note_text)
VALUES ('a2', NOW( ), 'hello' );
INSERT LOW_PRIORITY INTO productnotes(prod_id,note_date,note_text)
VALUES ('a3', NOW( ), 'home' );
VALUES 后边多个括号的值用逗号隔开。效率高。
INSERT INTO productnotes ( prod_id, note_date, note_text )
VALUE
( 'a1', NOW( ), 'year' ),
( 'b1', NOW( ), 'month' )
注意:VALUE 是 VALUES 的 synonym 没有区别。
3. 插入检索出的数据
INSERT SELECT
INSERT INTO productnotes ( prod_id, note_date, note_text )
SELECT prod_id,note_date,note_text FROM productnotes
第二十章 更新和删除数据
更新数据
更新表中的特定行,添加 WHERE 子句
UPDATE productnotes SET note_text = 'update hello', prod_id = 520
WHERE note_id = '3'
更新表中的所有行,不加 WHERE 子句
IGNORE 关键字,发生错误仍然继续更新
UPDATE IGNORE tablename ..
删除数据
从表中删除特定的行
DELETE FROM productnotes WHERE note_id = 1
从表中删除所有行
使用 TRUNCATE TABLE 提高效率,实际是直接删除原来的表再新建一个。不能有 where 子句
TRUNCATE TABLE productnotes
注意事项:
- 除非确实打算更新和删除每一行,否则绝对不要使用不带WHERE子句的UPDATE或DELETE语句
- 保证每个表都有主键
- 在对UPDATE或DELETE语句使用WHERE子句前,应该先用SELECT进行测试,保证过滤的是正确的记录
- 使用强制实施引用完整性的数据库,MySql 将不允许删除具有其他与其相关联的数据行
第二十一章 创建和操纵表
创建表
- 主键列不能允许 null
- SELECT LAST_INSERT_ID() 获取最后一次插入的自增 ID 值
- MySQL不允许使用函数作为默认值,它只支持常量
- 外键不能跨引擎
CREATE TABLE user
(
id INT NOT NULL AUTO_INCREMENT comment '用户id',
name CHAR ( 50 ) NOT NULL,
sex int DEFAULT 0,
PRIMARY KEY ( id )
) ENGINE = INNODB;
更新表
使用ALTER TABLE要极为小心,应该在进行改动前做一个完整的备份
ALTER TABLE `user` ADD address VARCHAR ( 255 );
ALTER TABLE `user` DROP address;
ALTER TABLE `user` CHANGE name username VARCHAR ( 100 ); -- 修改列名与类型
ALTER TABLE `user` MODIFY username VARCHAR(255) comment '用户名称'; -- 修改列属性
删除表
永久删除表,小心点啊
DROP TABLE test
重命名表
可以同时修改多个
RENAME TABLE `user` TO my_user ,tablename to newtablename;
第二十二章 视图
- 性能问题,每次使用视图,都会执行一个查询
- 视图不能索引,也不能有关联的触发器或默认值
- 可以通过单表视图更新、修改、删除表
- CREATE VIEW AS SELECT * FROM ...创建视图
- 使用 SHOW CREATE VIEW viewname;查看创建视图的语句。
- DROP VIEW viewname; 删除视图。
- CREATE OR REPLACE VIEW AS 更新或创建视图
CREATE VIEW vw_user AS
SELECT * FROM `user`
第二十三章 存储过程
使用存储过程比使用多条SQL语句要快
创建存储过程
不带参数的存储过程
CREATE PROCEDURE `pro_user`()
BEGIN
SELECT * FROM `user`;
END;
CALL pro_user -- 使用
使用命令行需注意:
如果命令行实用程序要解释存储过程自身内的;字符,则它们最终不会成为存储过程的成分,这会使存储过程中的SQL出现句法错误。解决办法是临时更改命令行实用程序的语句分隔符,如下所示:
DELIMITER // 告诉命令行实用程序使用//作为新的语句结束分隔符,可以看到标志存储过程结束的END定义为END// 而不是END;。 除\符号外,任何字符都可以用作语句分隔符
DELIMITER //
CREATE PROCEDURE `pro_user`()
BEGIN
SELECT * FROM `user`;
END //
DELIMITER;
使用存储过程
列出了查询结果
CALL pro_user
删除存储过程
DROP PROCEDURE pro_user
DROP PROCEDURE IF EXISTS pro_user -- 仅存在时删除,防止报错
使用参数
OUT 获取返回结果,只能是单列,想要获取结果集就不要使用 OUT参数。
注意:参数使用 id 时无法使用呢??不要和字段名一样
CREATE PROCEDURE pro_user ( OUT outid INT)
BEGIN
SELECT MAX( id ) INTO outid FROM `user`;
END;
CALL pro_user ( @outid);
SELECT @outid as id;
如果没有返回值 OUT ,但是有多个查询,会输出第一个的查询结果
DROP PROCEDURE IF EXISTS pro_user;
CREATE PROCEDURE pro_user ( in inname VARCHAR ( 255 ) )
BEGIN
SELECT * FROM `user`;
SELECT * FROM `user` WHERE `name` = inname;
END;
-- 使用
CALL pro_user ( 'ewjlf' );
IN 向存储过程中传入参数,
注意:传入参数也不能使用 id,不要和字段名一样
DROP PROCEDURE IF EXISTS pro_user;
CREATE PROCEDURE pro_user ( OUT outname VARCHAR ( 255 ), IN inid INT )
BEGIN
SELECT `name` INTO outname FROM `user` WHERE id = inid;
END;
建立智能存储过程
DROP PROCEDURE IF EXISTS pro_user;
CREATE PROCEDURE pro_user ( IN inid INT ) COMMENT '用户的存储过程'
BEGIN
-- 声明变量
DECLARE username VARCHAR(255);
DECLARE test int;
-- INTO 的位置可以是末尾
SELECT `name` FROM `user` WHERE id = inid INTO username;
-- if 语句
IF LENGTH( username ) > 0 THEN
SELECT '存在';
ELSE
SELECT '不存在';
END IF;
END;
-- 显示所有存储过程,也可以在后面加 like '存储过程名称' 这个查询条件
SHOW procedure STATUS
检查存储过程
SHOW CREATE PROCEDURE pro_user
自定义函数
参考:https://www.jb51.net/article/55019.htm##1
查看是否允许自定义函数,OFF 不允许
show variables like '%func%';
set global log_bin_trust_function_creators=1 -- 临时开启自定义函数功能
创建
CREATE FUNCTION <函数名> ( [ <参数1> <类型1> [ , <参数2> <类型2>] ] … )
RETURNS <类型>
<函数主体>
DROP FUNCTION IF EXISTS fun_user; -- 删除
CREATE FUNCTION fun_user(userid int) -- 创建
RETURNS varchar(255) -- 注意返回值是 RETURNS,有个 S
BEGIN
DECLARE username VARCHAR(255);
DECLARE result VARCHAR(255);
SELECT `name` FROM `user` WHERE id = userid INTO username;
-- if 语句
IF LENGTH( username ) > 0 THEN
SELECT '存在' into result;
ELSE
SELECT '不存在' INTO result;
END IF;
RETURN result;
END;
SELECT fun_user(22);
检查,与存储过程的使用方式一样
SHOW CREATE FUNCTION fun_user;
SHOW FUNCTION STATUS;
第二十四章 使用游标
MySQL游标只能用于存储过程(和函数)
游标主要用于交互式应用,其中用户需要滚动屏幕上的数据,并对数据进行浏览或做出更改
第二十五章 使用触发器
http://c.biancheng.net/view/2600.html
只支持 6 中触发器语句
begin |
insert |
update |
delete |
end |
insert |
update |
delete |
创建触发器
CREATE <触发器名> < BEFORE | AFTER >
<INSERT | UPDATE | DELETE >
ON <表名> FOR EACH Row <触发器主体>
可以引用 NEW 和 OLD 指代被操作前后的记录
CREATE TRIGGER before_insert BEFORE INSERT on user
FOR EACH ROW SET New.sex = 5;
第二十六章 管理事务处理
- 开启事务 START TRANSACTION
- 回滚 ROLLBACK
- 提交 COMMIT
- 保留点 SAVEPOINT NAME 搭配 ROLLBACK TO NAME
事务用来管理 INSERT、UPDATE、DELETE。
不能回退 SELECT、CREATE、DROP ,它们可以存在事务块中,但不可以撤销
隐含事务关闭 当COMMIT或ROLLBACK语句执行后,事务会自动关闭(将来的更改会隐含提交)。
保留点越多越好 可以灵活回退
释放保留点:ROLLBACK 或 COMMIT 后自动释放。MySQL 5 后可以使用 RELEASE SAVEPOINT 释放。
更改默认提交行为 SET autocommit = 0 设置为不自动提交,只在当前连接生效
START TRANSACTION;
SELECT * FROM `user`;
DELETE FROM `user` WHERE ID = 19
SAVEPOINT U20;
DELETE FROM `user` WHERE ID= 20
ROLLBACK TO U20;
COMMIT/ROLLBACK;
第二十七章 全球化和本地化
- 字符集 为字母和符号的集合
- 编码 某个字符集成员的内部表示
- 校对 规定字符如何比较的指令,_cs 区分大小写,_ci 不区分大小写
字符集和校对可以在系统管理安装、创建数据库、表、列的时候指定。
也可以在 select 语句中指定校对,实现想要的排序方式,或者是针对 GROUP BY、HAVING、聚集函数、别名
字符串可以使用 Cast() Convert() 转换字符集
SHOW CHARACTER SET; -- 显示可用的字符集、描述和默认校对
SHOW COLLATION; -- 显示所有可用校对,以及适用的字符集
SHOW VARIABLES LIKE 'character%'; -- 查看字符集
SHOW VARIABLES LIKE 'collation%'; -- 查看校对
第二十八章 安全管理
root 拥有对整个 MySQL 服务器的完全控制,只有在绝对需要时使用 root 用户
查看所有用户 存放在 mysql 这数据库的 user 表中
SELECT * from mysql.`user`
创建用户 最好使用 CREATE USER,不推荐使用 INSERT 直接操作 USER 表 ,也可以使用 GRANT
CREATE USER test IDENTIFIED BY '123' -- 创建用户,口令自动被加密
RENAME USER test TO test1; -- 重命名,仅 MySQL 5 后支持
删除用户 MySQL 5 之后会删除用户账号及相关权限。之前只删除用户账号,所以需要先用 REVOKE 删除相关权限
DROP USER test1;
设置权限
SHOW GRANTS FOR test; -- 显示拥有的权限
GRANT SELECT ON cloud.* TO test; -- 授予 cloud 数据库所有表上的只读权限
REVOKE SELECT ON cloud.* FROM test; -- 撤销权限
授权范围包括
- 整个服务器,使用 GRANT ALL 和 REVOKE ALL;
- 整个数据库,使用 ON database.*
- 特定的表,使用 ON database.table
- 特定的列
- 特定的存储过程。
注意:在使用 GRANT 和 REVOKE 时,用户账号必须存在,但对所涉及的对象没有这个要求。这允许管理员在创建数据库和表之前设计和实现安全措施。
这样做的副作用是,当某个数据库或表被删除时(用DROP语句),相关的访问权限仍然存在。而且,如果将来重新创建该数据库或表,这些权限仍然起作用。
更改口令
SET PASSWORD FOR test = PASSWORD('443'); -- 修改指定用户的密码,必须使用 PASSWORD() 函数加密
SET PASSWORD = PASSWORD('443'); -- 修改当前登录用户的口令
第二十九章 数据库维护
- 备份数据库
- 数据库维护
- 诊断启动问题
- 查看日志文件
- 错误日志 启动和关闭问题以及任意关键错误的细节,data/hostname.err
- 查询日志 它记录所有MySQL活动,data/hostname.log
- 二进制日志 它记录更新过数据(或者可能更新过数据)的所有语句,data/hostname-bin
- 缓慢查询日志,在 data/hostname-show.log 中
第三十章 改善性能
- 遵循数据库的硬件建议
- 数据库应该运行在转悠服务器上
- 需要按需调整内存分配、缓冲区大小等 SHOW VARIABLES;SHOW STATUS;
- 多个任务之间互相影响,通过 SHOW PROCESSLIST; 查看所有经常,使用 KILL 命令终止
- 编写同一条 SELECT 语句有多种方式,应该尝试联结、并、子查询等找出最佳方案
- 使用 EXPLAIN 显示 SELECT 语句的执行过程
- 一般来说,执行多条 sql 语句使用存储过程更快
- 使用正确的数据类型
- 检索的数据不要使用 *,应该按需检索
- 有的操作(包括INSERT)支持一个可选的 DELAYED 延时关键字,如果使用它,将把控制立即返回给调用程序,并且一旦有可能就实际执行该操作。异步??
- 添加索引,针对 WHERE ORDER BY 子句
- 索引会影响插入、删除、更新的性能,无必要则不使用
- 使用 UNION 代替 OR 语句
- 数据库是不断变化的实体。一组优化良好的表一会儿后可能就面目全非了。由于表的使用和内容的更改,理想的优化和配置也会改变,应该根据实际情况去调整。
- 最重要的规则就是,每条规则在某些条件下都会被打破。一切以实际场景为准。
参考《MySQL 必知必会》