MySQL 补充(来自MySQL必知必会)
MySQL 补充
SELECT 子句顺序
SELECT # 必须
FROM # 仅从表中选择数据时使用
WHERE # 仅从表中来过滤行级数据时使用
GROUP BY # 仅按组计算数据时使用
HAVING # 组级别的过滤
ORDER BY # 排序时使用
LIMIT # 限制检索的行数
DISTINCT 去重
DISTINCT 必须放在所有字段的前面,并且它的作用范围是后续的所有字段,而不是单独某个字段:
mysql> select * from B;
+----+------+------+
| id | name | aid |
+----+------+------+
| 1 | wang | 1 |
| 2 | han | 1 |
| 3 | li | 2 |
+----+------+------+
mysql> select distinct aid, name from B; # 作用于 (aid, name) 上,而不是仅仅 aid 上
+------+------+
| aid | name |
+------+------+
| 1 | wang |
| 1 | han |
| 2 | li |
+------+------+
mysql> select name, distinct aid from B; # distinct 必须放在所有字段前面,否则报错。
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'distinct aid from B' at line 1
Order by 排序
order by 可以对多个字段排序,它会先对第一个字段排序,如果第一个字段有重复相同的值,则对这个重复的值按照第二个字段排序...
正则表达式
mysql 也支持正则表达式,它和 like
关键字有些像,都可以匹配字段的值。
mysql 的正则表达式,如果需要转义某个字符,需要使用 \\
。如转义 .
需要: \\.
; 转义 \
自身需要:\\\
譬如:
mysql> select * from B;
+----+------+------+
| id | name | aid |
+----+------+------+
| 1 | wang | 1 |
| 2 | han | 1 |
| 3 | li | 2 |
| 4 | li. | NULL |
| 5 | aa | NULL |
+----+------+------+
mysql> select name from B where name regexp '\\.'; # 转义 .
+------+
| name |
+------+
| li. |
+------+
mysql> select name from B where name regexp '.an';
+------+
| name |
+------+
| wang |
| han |
+------+
mysql> insert into B(name, aid) values ('Wang', 1);
mysql> select name from B where name regexp binary 'Wang'; # 使用 binary 关键字来区分大小写(默认不区分大小写)
+------+
| name |
+------+
| Wang |
+------+
函数
更多函数,查看:https://www.runoob.com/mysql/mysql-functions.html
CONCAT 拼接字符
CONCAT(str1, str2, ...) 可以用来拼接字符
mysql> select * from B;
+----+------+------+
| id | name | aid |
+----+------+------+
| 1 | wang | 1 |
| 2 | han | 1 |
| 3 | li | 2 |
| 4 | li. | NULL |
| 5 | aa | NULL |
| 6 | Wang | 1 |
+----+------+------+
mysql> select concat(name, '(', aid, ')') from B;
+-----------------------------+
| concat(name, '(', aid, ')') |
+-----------------------------+
| wang(1) |
| han(1) |
| li(2) |
| NULL |
| NULL |
| Wang(1) |
+-----------------------------+
LENGTH
计算字符串的长度
mysql> select length('a');
+-------------+
| length('a') |
+-------------+
| 1 |
+-------------+
RTRIM
移除字符串右侧的空白符,同样的,还有:移除左侧空白符的 ltrim
, 以及移除左右两侧空白符的 trim
mysql> select length(rtrim('a '));
+----------------------+
| length(rtrim('a ')) |
+----------------------+
| 1 | # 长度变成 1 了
+----------------------+
UPPER, LOWER
将字符转换成大写或小写:
mysql> select upper('a'), lower('A');
+------------+------------+
| upper('a') | lower('A') |
+------------+------------+
| A | a |
+------------+------------+
LEFT
left(str, num), 截取左侧几个字符串:
mysql> select left('abc',2);
+---------------+
| left('abc',2) |
+---------------+
| ab |
+---------------+
同样的,还有 right
函数,可以截取右侧几位字符串
汇总数据
聚合函数(aggregate function),它是运行在行组(即一组数据)上的函数,来计算和返回单个值。常见的聚合函数有:
avg() # 平均值
count() # 行数
max() # 最大值
min() # 最小值
sum() # 总和
因此,上面的聚合函数,都可以在分组的情况下使用,因为他们都只返回单个值。
COUNT
count(*)
只统计行数(不管值是不是 NULL 都会算上)
count(column)
统计某一列有值的行数(忽略 null 值)
mysql> select * from B;
+----+------+------+
| id | name | aid |
+----+------+------+
| 1 | wang | 1 |
| 2 | han | 1 |
| 3 | li | 2 |
| 4 | li. | NULL |
| 5 | aa | NULL |
| 6 | Wang | 1 |
+----+------+------+
mysql> select count(aid) from B;
+------------+
| count(aid) |
+------------+
| 4 |
+------------+
子查询
子查询过滤
我们可以将一个查询结果,作用于另一个查询的 where 子句。
mysql> select * from B;
+----+------+------+
| id | name | aid |
+----+------+------+
| 1 | wang | 1 |
| 2 | han | 1 |
| 3 | li | 2 |
| 4 | li. | NULL |
| 5 | aa | NULL |
| 6 | Wang | 1 |
+----+------+------+
mysql> select name
-> from B
-> where aid in (select aid
-> from B
-> where name like 'li%');
+------+
| name |
+------+
| li |
+------+
子查询是从内而外的,先执行最里层的查询,然后将结果返回给外部的 where 子句,来进行外层的查询。
子查询不仅可以使用
IN
,还可以使用>, =, <>
等符号,前提是子查询返回的结果是单个值。
相关子查询
还有一种子查询,需要从外部获取信息,这种查询叫做相关子查询
mysql> select * from A;
+----+------+
| id | num |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
+----+------+
mysql> select * from B;
+----+------+------+
| id | name | aid |
+----+------+------+
| 1 | wang | 1 |
| 2 | han | 1 |
| 3 | li | 2 |
| 4 | li. | NULL |
| 5 | aa | NULL |
| 6 | Wang | 1 |
+----+------+------+
mysql> select id, (select count(*) from B where B.aid=A.id) as num from A;
+------+------+
| id | num |
+------+------+
| 1 | 3 |
| 2 | 1 |
| 3 | 0 |
+------+------+
先看外层查询:select ... from A
再看子查询:selct ... from B where B.aid=A.id
子查询中用到了外层的数据:A.id,因此这两个查询其实是相关的:即外层每查询一次,内层随着 A.id 的变化也跟着查询一次。
连接
UNION
UNION 可以用来连接多个查询结果,将其作为一个整体输出。
mysql> select * from A;
+----+------+
| id | num |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
+----+------+
mysql> select * from B;
+----+------+------+
| id | name | aid |
+----+------+------+
| 1 | wang | 1 |
| 2 | han | 1 |
| 3 | li | 2 |
| 4 | li. | NULL |
| 5 | aa | NULL |
| 6 | Wang | 1 |
+----+------+------+
mysql> select id from A
-> union
-> select id from B;'
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
+----+
6 rows in set (0.00 sec)
UNION 默认会将两个表中重复的记录进行去重。不想去重的话,使用
UNION ALL
使用 UNION 时,只能使用一个 GROUP BY 语句,不允许每个查询都拥有一个自己的 GROUP BY 语句。并且这个 GROUP BY 只能放在最后一个 SELECT 查询后面。
mysql> select id from A
-> union
-> select id from B
-> group by id; # 看似这个 group by 属于后一个查询,但其实它针对的是 UNION 联合后的全表进行排序。
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
+----+
存储过程
存储过程就是先将一些复杂的查询语句写成类似于函数的形式,这样我们每次直接调用这个存储过程,就能执行这些复杂的查询语句。
创建和使用存储过程
创建语法:
create procedure Func() # Func 是存储过程的名字,可以接受参数。
begin # BEGIN 和 END 来限制存储过程体
select ... from ... where...; # 存储过程体
end;
使用:
CALL Func(); # 使用上面定义的 Func 这个存储过程
示例:
mysql> delimiter // # 修改默认的定界符
mysql> create procedure test()
-> begin
-> select id from B; # 遇到 ; 也不会认为语句结束
-> end // # 这里语句才结束
mysql> delimiter ; # 将定界符重新修改回来
mysql> call test(); # 调用存储过程
+----+
| id |
+----+
| 4 |
| 5 |
| 1 |
| 2 |
| 6 |
| 3 |
| 7 |
+----+
注意:mysql 默认的语句定界符是
;
但是我们在存储过程体中也要写;
,因此 MySQL 的命令行程序遇到存储过程体中的;
就会认为语句结束了,造成语法错误。因此,我们实现先将默认的定界符改成//
,最后再改回来,就行了。
删除
mysql> drop procedure test; # 删除 test 这个procedure
带参数的存储过程
从存储过程获取返回值
mysql> delimiter //
mysql> create procedure func(out arg1 int) # out 定义了要给出的结果参数,int是参数返回的类型;当然你可以定义多个参数:out arg1 type, out arg2 type, ...
-> begin
-> select max(id) into arg1 # into 关键字指定了 max(id) 的值赋值给 arg1
-> from B;
-> end//
mysql> delimiter ;
mysql> call func(@max_price); # 传递一个参数用来接收值
mysql> select @max_price;
+------------+
| @max_price |
+------------+
| 7 |
+------------+
注意:存储过程的参数,不能返回多行或多列这种数据集,只能接受单个值
out
关键字用来定义一个要从存储过程返回的参数(按理说不应该叫参数,因为它被用作返回值),语法是out arg_name type
into
关键字用来赋值
给存储过程输入值
mysql> delimiter //
mysql> create procedure func2(in arg1 int, out arg2 int)
-> begin
-> select count(*) from B where id=arg1 into arg2;
-> end//
mysql> delimiter ;
mysql> call func2(1, @output); # 第一个数字 1 代表了传递给存储过程的 arg1 参数
mysql> select @output;
+---------+
| @output |
+---------+
| 1 |
+---------+
1 row in set (0.00 sec)
高级语法
-- this is comment # -- 是注释符号,后面的都是注释
DECLARE # 声明一个变量和其类型,也可以设置默认值: declare arg1 int default 1
mysql> delimiter //
mysql> create procedure fun3(out x int)
-> -- this is comment
-> begin
-> declare y int default 2; # 声明一个变量
-> select max(id*2) from A into x;
-> end//
mysql> delimiter ;
mysql> call fun3(@x);
mysql> select @x;
+------+
| @x |
+------+
| 8 |
+------+
触发器
触发器的作用,就是当一个表发生更改时,会自动触发我们定义的触发器的操作,从而可以自动进行一些额外的操作
语法:
create trigger <trigger_name> <time> <operation> on <table> for each row # for each row 意思是针对这张表的某一行,都会激活触发器
<other_operate>;
trigger_name: 就是普通的触发器名字,自定义
time: 指定触发器何时触发:
before
,after
operation: 何种操作:
insert
,update
,delete
table: 触发器设置在哪个表上
other_operate: 就是其他查询操作
下面是一个例子:
mysql> create trigger new_add1 # 创建一个名为 new_add1 的触发器
-> after insert on A for each row # 这个触发器会在插入 A 表之后执行
-> update B set name=0 where id=1; # 这是触发器自动执行的操作:更新 B 表id=1 的 name 字段
执行插入 A 表的操作:
mysql> insert into A(num) values(2);
Query OK, 1 row affected (0.17 sec)
mysql> select * from B where id=1;
+----+------+------+
| id | name | aid |
+----+------+------+
| 1 | 0 | 1 | # name 变成了 0
+----+------+------+
事务
所谓的事务,就是一组 SQL 语句。它要么执行成功,要么完全不执行。试想一下你银行转账给别人,钱已经从你的账户扣除了,但是银行出现故障导致对方没收到钱,这种情况是任何人都无法忍受的。因此,像这种操作,要么就完全执行成功:你转出去,对方收到。要么就没转成功,你钱没少,对方也没收到。
事务(transaction): 一组SQL语句
回退(rollback):撤销指定的SQL语句
提交(commit):将未存储的SQL结果存入数据库
保留点(savepoint):临时存档,可以对它进行回退
开始事务和回退
start transaction
标志着事务的开始。
mysql> select * from B;
+----+------+------+
| id | name | aid |
+----+------+------+
| 1 | 0 | 1 |
| 2 | han | 1 |
| 3 | li | 2 |
| 4 | li. | NULL |
| 5 | aa | NULL |
| 6 | Wang | 1 |
| 7 | aab | 2 |
+----+------+------+
mysql> start transaction; # 开始事务
mysql> delete from B; # 将 B 表整个清空
mysql> select * from B; # 清空了,没查询到数据
Empty set (0.00 sec)
mysql> rollback; # 回退事务
Query OK, 0 rows affected (0.08 sec)
mysql> select * from B; # 表 B 的内容又回来了
+----+------+------+
| id | name | aid |
+----+------+------+
| 1 | 0 | 1 |
| 2 | han | 1 |
| 3 | li | 2 |
| 4 | li. | NULL |
| 5 | aa | NULL |
| 6 | Wang | 1 |
| 7 | aab | 2 |
+----+------+------+
事务可以用来处理
update
,delete
,insert
rollback 之后,事务会自动关闭。
提交
commit
可以用来提交一个事务,即认为事务完成了。
mysql> start transaction;
mysql> delete from B where id=7;
mysql> delete from B where id=8;
mysql> commit;
假设第一个删除语句成功,第二个删除语句失败,那么commit 也不会提交(一个事务必须全部成功,才能提交)
commit 后事务会自动关闭
保留点
我们可以在事务中创建保留点,然后我们在这个事务后续处理过程种,可以随时回退到这个存档点。
mysql> select * from B;
+----+------+------+
| id | name | aid |
+----+------+------+
| 1 | 0 | 1 |
| 2 | han | 1 |
| 3 | li | 2 |
| 4 | li. | NULL |
| 5 | aa | NULL |
| 6 | Wang | 1 |
+----+------+------+
mysql> start transaction;
mysql> delete from B where id=6;
mysql> savepoint s1;
mysql> delete from B where id=5;
mysql> rollback to s1;
mysql> select * from B;
+----+------+------+
| id | name | aid |
+----+------+------+
| 1 | 0 | 1 |
| 2 | han | 1 |
| 3 | li | 2 |
| 4 | li. | NULL |
| 5 | aa | NULL |
+----+------+------+
mysql> commit;
全球化和本地化
字符集:字母和符号的集合
编码:就是编码
校对:如何对字符集进行比较,如排序(大小写怎么排序)
show character set; # 查看所有的字符集
show collation; # 查看所有的校对 (_cs 后缀代表区分大小写, ci 代表忽略大小写)
创建表
针对某个表设置字符集和校对:
create table <table_name> (columns ...) default character set <字符集> collate <校对>
针对某个字段设置字符集和校对:
create table <table_name> (
id int,
name varchar(10) character set latin1 collate latin1_general_ci # 对某个字段也可以设置字符集和校对
);
查询某个字段时,可以临时给它指定一个校对方式:
select * from <table_name> order by name collate latin1_general_cs; # 区分大小写
安全管理
用户管理
mysql 的用户信息表,位于名为 mysql 的数据库中:
mysql> use mysql;
Database changed
mysql> select user from user;
+------------------+
| user |
+------------------+
| mysql.infoschema |
| mysql.session |
| mysql.sys |
| root |
+------------------+