MySQL必知必会

本文链接
http://alex-my.xyz/books/database/MySQL必知必会

http://blog.csdn.net/alex_my/article/details/72357498

1 基础知识

1 主键

  • 唯一标识表中每行的这个列(这组列)称为主键。
  • 应该总是定义主键,虽然并不总是需要主键。
  • 任意两行都不具有相同的主键值。
  • 每一行都必须具有一个主键值,不可为NULL。

2 常用命令

  • SHOW DATABASES;
  • SHOW TABLES;
  • SHOW COLUMNS FROM table;
  • SHOW STATUS;
  • SHOW CREATE DATABASE database;
  • SHOW CREATE TABLE table;

2 检索数据

除非确实需要绝大部分列或全部列,否则最好不使用通配符* 来获取所有的列。检索不需要的列通常会降低搜索和应用程序的性能。

1 DISTINCT和GROUP BY

SELECT DISTINCT `role_id` FROM user;
SELECT `role_id` FROM user GROUP BY `role_id`;
  • 二者都可以达到去重的效果。
  • DISTINCT把列中的全部内容存储到内存中,可以理解为一个hash,最后的到hash中的key就可以得到结果。比较耗内存。
  • GROUP BY先将列排序,然后去重。排序比较耗时间。

2 LIMIT

从0开始算

SELECT `role_id` FROM user LIMIT 5 OFFSET 3;
SELECT `role_id` FROM user LIMIT 3, 5;

以上两条命令都表示从3开始的5行。

3 排序数据

默认为升序 ASC

SELECT `role_id`, `account_id` FROM user_pay ORDER BY `account_id`, `role_id` DESC LIMIT 20;

以上语句中, account_id默认为升序排列,也可以写上ASC。

4 过滤数据

1 IN操作符

SELECT * FROM user WHERE role_id IN (1000001, 1000002);

2 NOT操作符

SELECT * FROM user WHERE role_id IN (1000001, 1000002) LIMIT 10;

3 LIKE操作符

SELECT * FROM user WHERE name LIKE 't%';
SELECT * FROM user WHERE name LIKE 't_';    -- t1, t2
SELECT * FROM user WHERE name LIKE 't__';   -- t123, t34
  • 以上两句都是模糊匹配用户名以t开头。
  • %: 匹配任意0个或者多个字符。
  • _: 一个_匹配1个任意字符,且必须有一个。

5 正则表达式搜索

MYSQL仅支持多数正则表达式实现的一个很小的子集。

1 基本字符匹配

SELECT name FROM user WHERE name REGEXP 't';    -- t, t1, t2
SELECT name FROM user WHERE name REGEXP 't.';   -- t1, t2
  • .表示匹配任意一个字符。
  • LIKE和REGEXP区别:
  • LIKE 要求整个列匹配(使用通配符除外), REGEXP只要列中某个片段匹配即可。
  • 假设有用户名为s123。则以下例子中, LIKE没有得到结果。
SELECT name FROM user WHERE name LIKE 's1';     -- 没有结果
SELECT name FROM user WHERE name REGEXP 's1';   -- s123

2 OR匹配

SELECT name FROM user WHERE name REGEXP 's1|s2' ORDER BY name; -- s123, s2, s234

使用|功能上类似于SELECT中的OR语句。多个OR语句可以使用正则表达式替代,更简洁。

3 匹配几个字符之一

SELECT name FROM user WHERE name REGEXP 's[1238]' ORDER BY name;  -- s123, s2, s234, s89

相当于

SELECT name FROM user WHERE name REGEXP 's1|s2|s3|s8' ORDER BY name;

也可以添加^,来匹配除指定以外的内容

SELECT name FROM user WHERE name REGEXP 's[^1238]' ORDER BY name;  -- s4, s5

4 匹配范围

SELECT name FROM user WHERE name REGEXP 's[1-8]' ORDER BY name;  -- s123, s2, s89..

SELECT name FROM user WHERE name REGEXP '[a-z][1-8]' ORDER BY name;  -- a1, b2, c3

5 匹配特殊字符

为了匹配特殊字符,必须用\\为前导。

SELECT name FROM user WHERE name REGEXP 's\\-' ORDER BY name;  -- s-5

\\也用来引用具有特殊含义的字符

特殊字符 含义
\\f 换页
\\n 换行
\\r 回车
\\t 制表
\\v 纵向制表

多数正则表达式使用\转义特殊字符,以便能使用这些字符本身。但MySQL要求用\\
MySQL解释一个,正则表达式解释另外一个。

6 匹配字符类

为了方便工作,可以使用预定义的字符集

说明
[:alnum:] 任意字母和数字 ([a-zA-Z0-9])
[:alpha:] 任意字符 ([a-zA-Z])
[:blank:] 空格和指标 (\\t)
[:cntrl:] ASCII控制字符 (ASCII 0~31, 127)
[:digit:] 任意数字 ([0-9])
[:graph:] 与[:print:]相同,但不包括空格
[:lower:] 任意小写字母 ([a-z])
[:print:] 任意可打印的数字
[:punct:] 同时不在[:alnum:][:cntrl:]中的任意字符
[:space:] 包括空格在内的任意空白字符 ([\\t\\n\\r\\t\\v])
[:upper:] 任意大写字母 ([A-Z])
[:xdigit:] 任意十六进制数字 ([a-fA-F0-9])

示例:

SELECT name FROM user WHERE name REGEXP '[[:alpha:]]1' ORDER BY name; -- h1, m1, s123

7 匹配多个实例

字符 说明
* 0个或多个匹配
+ 1个或多个匹配 ({1, })
? 0个或1个匹配 ({0, 1})
{n} 指定数目的匹配
{n, } 不少于指定数目的匹配
{n, m} 匹配数目范围, m 不超过255
SELECT name FROM user WHERE name REGEXP '[[:digit:]]{4}' ORDER BY name; -- s4444, 21111

8 定位符

元字符 说明
^ 文本的开始
$ 文本的结尾
[[:<:]] 词的开始
[[:>:]] 词的结尾

* 示例1
假设要找到以字母开头的用户名

SELECT  name FROM user WHERE name REGEXP '[a-zA-Z]';

以上语句将会在文本任意位置进行查找匹配,并不符合以字母开头这依规定. 这里可以使用^

SELECT  name FROM user WHERE name REGEXP '^[a-zA-Z]';

6 创建计算字段

存储在表中的数据不一定是应用程序所需要的。我们可以直接从数据库中检索出转换,计算或格式化过的数据。而不是检索出原始数据然后在应用程序中重新格式化。

1 拼接 CONCAT

表中含有role_id, name字段,应用程序需要这样的格式 role_name(role_id)

SELECT CONCAT(name, '(', role_id, ')') FROM user LIMIT 1;   -- s123 (1000001)
SELECT CONCAT(RTRIM(name), '(', role_id, ')') FROM user LIMIT 1;   -- s123(1000001)
  • RTRIM()函数去掉了值右边的所有空格。其余有LTRIM(), TRIM()

2 别名 AS

拼接处的结果没有名字,应用程序没法引用。可以使用别名解决这个问题。

SELECT CONCAT(name, '(', role_id, ')') AS info FROM user LIMIT 1;

这样,应用程序就可以使用info这个列,就像它本来就存在于表中一样。

3 执行算术计算

假设用户充值了money(元),每元可以换成10个代币,这里通过计算直接得出获得的总代币。

SELECT role_id, money, money * 10 AS total_gold FROM user LIMIT 10;

7 使用数据处理函数

1 字符串函数

函数 说明 示例 结果
CHAR_LENGTH(S) 返回字符串s字符数 SELECT CHAR_LENGTH(‘abc 你好’); 6
LENGTH(S) 返回字符串s的长度 SELECT LENGTH(‘abc 你好’); 10
CONCAT(S1,S2,…) 合并为一个字符串 SELECT CONCAT(‘hello’, ’ abc’); hello abc
CONCAT_WS(x, s1, s2,…) 同CONCAT,但会加上x SELECT CONCAT_WS(‘+’, ‘1’, ‘2’, ‘3’); 1+2+3
INSERT(s1, x, length, s2) 将字符串s2替换s1的x位置开始长度为length的字符串 SELECT INSERT(‘abcdefg’, 2, 3, ‘123’); a123efg
UPPER(s) 将字符串s的所有字母变成大写字母 SELECT UPPER(‘abcd’); ABCD
LOWER(s) 将字符串s的所有字母变成小写字母 SELECT LOWER(‘ABCD’); abcd
LEFT(s, n) 返回字符串s的前n个字符 SELECT LEFT(‘abcdef’, 3); abc
RIGHT(s, n) 返回字符串s的后n个字符 SELECT RIGHT(‘abcdef’, 3); def
LPAD(s1, length, s2) 字符串s2来填充s1的开始处,使字符串长度达到length SELECT LPAD(‘abc’, 8, ‘123’); 12312abc
RPAD(s1, length, s2) 字符串s2来填充s1的结尾处,使字符串的长度达到length SELECT RPAD(‘abc’, 8, ‘123’); abc12312
LTRIM(s) 去掉字符串s开始处的空格 SELECT LTRIM(’ abc ‘); ‘abc ‘
RTRIM(s) 去掉字符串s结尾处的空格 SELECT RTRIM(’ abc ‘); ’ abc’
TRIM(s) 去掉字符串s开始和结尾处的空格 SELECT TRIM(’ abc ‘); ‘abc’
TRIM(s1 FROM s) 去掉字符串s中开始处和结尾处的字符串s1 SELECT TRIM(‘-’ FROM ‘—hello–’); hello
REPEAT(s, n) 将字符串s重复n次 SELECT REPEAT(‘abc’, 3); abcabcabc
SPACE(n) 返回n个空格 SELECT SPACE(3); ‘   ’
REPLACE(s, s1, s2) 将字符串s2替代字符串s中的字符串s1 SELECT REPLACE(‘abcdef’, ‘abc’, ‘12’); 12def
STRCMP(s1, s2) 比较字符串s1和s2 SELECT STRCMP(‘abc’, ‘abc’); 0
STRCMP(s1, s2) 比较字符串s1和s2 SELECT STRCMP(‘abc’, ‘abcd’); -1
STRCMP(s1, s2) 比较字符串s1和s2 SELECT STRCMP(‘abc’, ‘ab’); 1
SUBSTRING(s, n, length) 获取从字符串s中的第n个位置开始长度为length的字符串 SELECT SUBSTRING(‘abcdefg’, 2, 3); bcd
MID(s, n, length) 同SUBSTRING SELECT MID(‘abcdefg’, 3, 2); cd
LOCATE(s1, s) 从字符串s中获取s1的开始位置 SELECT LOCATE(‘de’, ‘abcdefg’); 4
POSITION(s1, s) 从字符串s中获取s1的开始位置 SELECT POSITION(‘de’ IN ‘abcdefg’); 4
INSTR(s, s1) 从字符串s中获取s1的开始位置 SELECT INSTR(‘abcdefg’, ‘de’); 4
REVERSE(s) 将字符串s的顺序反过来 SELECT REVERSE(‘a,b,c,d,e,f’); f,e,d,c,b,a
ELT(n, s1, s2, …) 返回第n个字符串 SELECT ELT(3, ‘abc’, ‘def’, ‘ghi’, ‘jkl’); ghi
EXPORT_SET(…) 见示例 SELECT EXPORT_SET(6, ‘y’, ‘n’, ‘_’, 3); n_y_y
FIELD(s, s1, s2, …) 返回第一个与字符串s匹配的字符串位置 SELECT FIELD(‘b’, ‘a’, ‘b’, ‘c’); 2
FIND_IN_SET(str, str_list) 见示例 SELECT FIND_IN_SET(‘4’, ‘6,5,4,3,2,1’); 3

2 数学函数

函数 说明 示例 结果
ABS(x) 返回x的绝对值
CEIL(x) 返回大于或等于x的最小整数
CEILING(x) 返回大于或等于x的最小整数
FLOOR(x) 返回小于或等于x的最大整数
RAND() 返回0->1的随机数
RAND(x) 返回0->1的随机数,x值相同时返回的随机数相同
SIGN(x) 返回x的符号,x是负数、0、正数分别返回-1、0和1
PI() 返回圆周率(3.141593)
TRUNCATE(x, y) 返回数值x保留到小数点后y位的值(不会四舍五入)
ROUND(x) 返回离x最近的整数
ROUND(x, y) 保留x小数点后y位的值(四舍五入)
POW(x, y) 返回x的y次方
POWER(x, y) 返回x的y次方
SQRT(x) 返回x的平方根
EXP(x) 返回e的x次方
MOD(x, y) 返回x除以y以后的余数
LOG(x) 返回自然对数(以e为底的对数)
LOG10(x) 返回以10为底的对数
RADIANS(x) 将角度转换为弧度
DEGREES(x) 将弧度转换为角度
SIN(x) 求正弦值(参数是弧度)
ASIN(x) 求反正弦值(参数是弧度)
COS(x) 求余弦值(参数是弧度)
ACOS(x) 求反余弦值(参数是弧度)
TAN(x) 求正切值(参数是弧度)
ATAN(), ATAN2() 求反正切值(参数是弧度)
COT() 求余切值(参数是弧度)

3 日期时间函数

函数 说明 示例 结果
CURDATE(), CURRENT_DATE() 返回当前日期 SELECT CURRENT_DATE(); 2017-05-11
CURTIME(), CURRENT_TIME 返回当前时间 SELECT CURRENT_TIME(); 19:01:11
NOW() 返回当前日期和时间 SELECT NOW(); 2017-05-11 19:01:30
CURRENT_TIMESTAMP() 返回当前日期和时间 同上
LOCALTIME() 返回当前日期和时间 同上
SYSDATE() 返回当前日期和时间 同上
LOCALTIMESTAMP() 返回当前日期和时间 同上
UNIX_TIMESTAMP() 以UNIX时间戳的形式返回当前时间 SELECT UNIX_TIMESTAMP(); 1494500521
UNIX_TIMESTAMP(d) 将时间d以UNIX时间戳的形式返回 SELECT UNIX_TIMESTAMP(‘2017-05-11 19:02:01’); 1494500521
FROM_UNIXTIME(d) 将UNIX时间戳的时间转换为普通格式的时间 SELECT FROM_UNIXTIME(1494500521); 2017-05-11 19:02:01
UTC_DATE() 返回UTC日期 SELECT UTC_DATE(); 2017-05-11
UTC_TIME() 返回UTC时间 SELECT UTC_TIME(); 11:06:13
MONTH(d) 返回日期d中的月份值,1->12 SELECT MONTH(‘2017-05-11’); 5
MONTHNAME(d) 返回日期当中的月份名称 SELECT MONTHNAME(‘2017-05-11’); May
DAYNAME(d) 返回日期d是星期几 SELECT DAYNAME(‘2017-05-11 19:07:12’); Thursday
DAYOFWEEK(d) 日期d今天是星期几,1星期日,2星期一 SELECT DAYOFWEEK(‘2017-05-11’); 5
WEEKDAY(d) 日期d今天是星期几,0表示星期一,1表示星期二 SELECT WEEKDAY(‘2017-05-11’); 3
WEEK(d),WEEKOFYEAR(d) 计算日期d是本年的第几个星期,范围是0->53 SELECT WEEK(‘2017-05-11’); 19
DAYOFYEAR(d) 计算日期d是本年的第几天 SELECT DAYOFYEAR(‘2017-05-11’); 131
DAYOFMONTH(d) 计算日期d是本月的第几天 SELECT DAYOFMONTH(‘2017-05-11’); 11
QUARTER(d) 返回日期d是第几季节,返回1->4 SELECT QUARTER(‘2017-05-11’); 2
HOUR(t) 返回t中的小时值 SELECT HOUR(‘2017-05-11 19:11:23’); 19
MINUTE(t) 返回t中的分钟值 SELECT MINUTE(‘2017-05-11 19:11:23’); 11
SECOND(t) 返回t中的秒钟值 SELECT SECOND(‘2017-05-11 19:11:23’); 23
EXTRACT(type FROM d) 从日期d中获取指定的值,type指定返回的值(见下文) SELECT EXTRACT(WEEK FROM ‘2017-05-11 19:11:23’); 19
TIME_TO_SEC(t) 将时间t转换为秒 SELECT TIME_TO_SEC(‘19:11:23’); 69083
SEC_TO_TIME(s) 将以秒为单位的时间s转换为时分秒的格式 SELECT SEC_TO_TIME(69083); 19:11:23
TO_DAYS(d) 计算日期d距离0000年1月1日的天数 SELECT TO_DAYS(‘2017-05-11 19:11:23’); 736825
FROM_DAYS(n) 计算从0000年1月1日开始n天后的日期 SELECT FROM_DAYS(736825); 2017-05-11
DATEDIFF(d1,d2) 计算日期d1->d2之间相隔的天数 SELECT DATEDIFF(‘2017-05-11’, ‘2017-05-12’); -1
ADDDATE(d,n) 计算其实日期d加上n天的日期 SELECT ADDDATE(‘2017-05-11 19:11:23’, 3); 2017-05-14 19:11:23
ADDDATE(d,INTERVAL expr type) 计算起始日期d加上一个时间段后的日期 SELECT ADDDATE(‘2017-05-11 19:11:23’, INTERVAL 3 HOUR); 2017-05-11 22:11:23
DATE_ADD(d,INTERVAL expr type) 同上 SELECT DATE_ADD(‘2017-05-11 19:11:23’, INTERVAL 10 HOUR); 2017-05-12 05:11:23
SUBDATE(d,n) 日期d减去n天后的日期 SELECT SUBDATE(‘2017-05-12 05:11:23’, 13); 2017-04-29 05:11:23
SUBDATE(d,INTERVAL expr type) 日期d减去一个时间段后的日期 SELECT SUBDATE(‘2017-04-29 05:11:23’, INTERVAL 10 MINUTE); 2017-04-29 05:01:23
ADDTIME(t,n) 时间t加上n秒的时间 SELECT ADDTIME(‘2017-04-29 05:01:23’, 30); 2017-04-29 05:01:53
SUBTIME(t,n) 时间t减去n秒的时间 SELECT SUBTIME(‘2017-04-29 05:01:53’, 30); 2017-04-29 05:01:23
DATE_FORMAT(d,f) 按表达式f的要求显示日期d SELECT DATE_FORMAT(‘2017-04-29 05:01:23’, ‘%Y-%m-%d’); 2017-04-29
TIME_FORMAT(t,f) 按表达式f的要求显示时间t SELECT TIME_FORMAT(‘2017-04-29 05:01:23’, ‘%r’); 05:01:23 AM

* type的值可以为:


MICROSECOND
SECOND
MINUTE
HOUR
DAY
WEEK
MONTH
QUARTER
YEAR
SECOND_MICROSECOND
MINUTE_MICROSECOND
MINUTE_SECOND
HOUR_MICROSECOND
HOUR_SECOND
HOUR_MINUTE
DAY_MICROSECOND
DAY_SECOND
DAY_MINUTE
DAY_HOUR
YEAR_MONTH

4 条件判断函数

  • IF (expr, v1, v2);

    SELECT IF (1 > 0, 'Y', 'N');    -- Y
  • IFNULL(v1, v2);
    如果v1不为NULL, 返回v1,否则返回v2

    SELECT IFNULL('a', 'b');    -- a

5 系统信息函数

函数 说明 示例 结果
VERSION() 返回数据库的版本号 SELECT VERSION(); 5.7.11
CONNECTION_ID() 返回服务器的连接数 SELECT CONNECTION_ID(); 13
DATABASE() 返回当前数据库名 SELECT DATABASE(); database-learn
USER() 返回当前用户 SELECT USER(); root@localhost
CHARSET(s) 返回字符串s的字符集 SELECT CHARSET(“123”); utf8
COLLATION(s) 返回字符串s的字符排列方式 SELECT COLLATION(“a123”); utf8_general_ci
LAST_INSERT_ID() 返回最近生成的AUTO_INCREMENT值 SELECT LAST_INSERT_ID(); 0

8 分组数据

1 数据分组

假设要获取用户的充值次数,最低充值额度,最高充值额度,平均充值额度,可以用以下命令:

SELECT role_id, COUNT(*) AS num, MIN(money) as min_money, MAX(money) as max_money, AVG(money) AS avg_money FROM user_pay;

以上得出的是总的信息,如果要获取每个用户的这些信息,就可以使用分组了。

SELECT role_id, COUNT(*) AS num, MIN(money) as min_money, MAX(money) as max_money, AVG(money) AS avg_money FROM user_pay GROUP BY role_id ORDER BY num;

以上按照每个用户来计算结果。

  • 需要注意的是,GROUP BY 必须出现在 WHERE 之后,ORDER BY 之前
  • 可以使用WITH ROLLUP得到汇总的值
    SELECT role_id, COUNT(*) AS num, MIN(money) as min_money, MAX(money) as max_money, AVG(money) AS avg_money FROM user_pay GROUP BY role_id WITH ROLLUP;

    以上在在结果的最后,会附上总的结果。

2 分组过滤

假设只需要得到充值2次(包含)以上用户的数据,则需要使用HAVING来过滤。

SELECT role_id, COUNT(*) AS num, MIN(money) as min_money, MAX(money) as max_money, AVG(money) AS avg_money FROM user_pay GROUP BY role_id HAVING num >= 2 ORDER BY num;
  • 注意HAVING跟GROUP BY后面。
  • 也可以同时使用WHERE和HAVING。
    SELECT role_id, COUNT(*) AS num, MIN(money) as min_money, MAX(money) as max_money, AVG(money) AS avg_money FROM user_pay WHERE time >= 1483200000 GROUP BY role_id HAVING num >= 2 ORDER BY num;

    以上通过WHERE新增了条件,2017年以来充值的。

  • 当sql_mode为ONLY_FULL_GROUP_BY需要注意
    • 查看sql_mode值

      SELECT @@sql_mode;

      结果:

      ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
    • 在sql_mode=ONLY_FULL_GROUP_BY的模式下,以下句子报错
      SELECT role_id, money FROM user_pay GROUP BY role_id;

      错误: SELECT list is not in GROUP BY clause and contains nonaggregated column ...
      表中的列,出现在SELECT中时,也得出现在GROUP BY中。

      SELECT role_id, money FROM user_pay GROUP BY role_id, money;

      同样,ORDER BY也需要注意这个问题。

3 SELECT字句顺序

SELECT > FROM > WHERE > GROUP BY > HAVING > ORDER BY > LIMIT

9 子查询

1 子查询过滤

假设要得出充值用户的用户信息

SELECT role_id, name FROM user WHERE role_id in (SELECT role_id FROM user_pay);
  • 在SELECT语句中,子查询总是从内向外处理。
  • 需要保证WHERE语句中需要和子SELECT语句中有相同数目的列。二者名称可以不相同。
    ... WHERE role_id in (SELECT role_id ...)
    ... WHERE role_id in (SELECT r_id ...)

2 做为计算字段使用子查询

假设要得出用户的充值次数(user_pay)以及用户信息(user)

SELECT  role_id,
        name,
        (SELECT COUNT(*)
         FROM user_pay
         WHERE user_pay.role_id = user.role_id) AS recharge_count
FROM user
LIMIT 10;

10 联结

1 内联结

同9.2 假设要得出用户的充值次数(user_pay)以及用户信息(user), 以下两种方法都可以获得结果。

使用WHERE子句

SELECT role_id, COUNT(money)
FROM user, user_pay
WHERE user.role_id = user_pay.rid
GROUP BY role_id;

使用INNER JOIN

SELECT  role_id,
        COUNT(money)
FROM user
INNER JOIN user_pay
ON user_pay.role_id = user.role_id
GROUP BY role_id;
  • ANSI SQL规范首选INNER JOIN。

2 外联结

外联结使用OUTER JOIN来表示。
必须在OUTER 前加上LEFT或RIGHT关键字。OUTER可以省略不写。
LEFT: 表示选中OUTER左侧表的所有行。
RIGHT: 表示选中OUTER右侧表的所有行。

SELECT a.role_id, SUM(b.money) AS total_recharge
FROM user a
LEFT JOIN user_pay b
ON a.role_id = b.role_id
GROUP BY a.role_id;

以上信息获取用户的充值信息,如果有用户没有充值,则total_recharge=NULL。
如果使用RIGHT JOIN,如果user_pay中有用户数据在user表中找不到,则role_id=NULL。

11 组合查询

1 UNION

假设需要获取充值额度为30的用户, 以及渠道为1001的用户,使用组合查询:

SELECT role_id, money FROM user_pay WHERE money = 30
UNION
SELECT role_id, money FROM user_pay WHERE channel_id = 1001;
  • 组合使用UNION将独立的SELECT相连。
  • 每个SELECT查询都必须包含相同的列,表达式或函数。但次序不必相同。

2 UNION ALL

UNION从查询结果中自动去除了重复的行。比如渠道1001也有人充值30的。
如果不想被去除重复的行,可以使用UNION ALL。

3 组合查询结果排序

可以在最后一条的SELECT后添加ORDER BY语句对结果进行排序。

12 全文本搜索

1 引擎支持

  • MyISAM和InnoDB(5.6)都支持全文本搜索。
    TODO

13 视图

视图可以简化操作,保护数据。

1 创建视图

  • 使用CREATE VIEW创建视图。
  • 使用DROP VIEW删除视图。
  • 这边使用 CREATE OR REPLACE VIEW
  • 创建一个视图,该视图从用户表(user), 用户充值表(user_pay)获取用户基本信息,总充值额度。
    CREATE OR REPLACE VIEW user_pay_info AS
    SELECT b.role_id, b.name, SUM(a.money) AS total_money
    FROM user_pay a
    RIGHT JOIN user b
    ON a.role_id = b.role_id
    GROUP BY b.role_id;

    使用SHOW TABLES可以发现多了一个表,user_pay_info。

2 使用视图 SELECT

  • 创建好视图后,再想获得用户充值信息,可以通过以下语句:

    SELECT * FROM user_pay_info;

    十分便捷。

  • 虽然表面看是从user_pay_info中获取数据,但实际上仍然是从user, user_pay中获取数据。

3 更新视图 UPDATE

视图中存在以下操作,则不可更新:

  • 分组 (GROUP BY, HAVING)
  • 联结
  • 子查询
  • 聚集函数 (MIN, COUNT, SUM)
  • DISTINCT

但凡MySQL不能确定能够正确更新到实际表(user, user_pay),则不允许进行视图更新。
一般,应该将视图用于检索,而不用于更新。

14 存储过程

相当于调用预编译好的sql集合。

1 创建存储过程 CREATE PROCEDURE

假设要知道每个用户的充值总额

CREATE PROCEDURE user_pay_total()
BEGIN
    SELECT role_id, SUM(money) AS total_recharge
    FROM user_pay
    GROUP BY role_id;
END 

以上就创建好了。
需要注意的是,如果在命令行工具中直接用以上语句创建,会报错。
因为命令行工具也用;做为分隔符,sql语句中也是用;做为分隔符,存在冲突。
是用 DELIMITER 可以自定义命令行工具的分隔符

DELIMITER //
CREATE PROCEDURE user_pay_total()
BEGIN
    SELECT role_id, SUM(money) AS total_recharge
    FROM user_pay
    GROUP BY role_id;
END //
DELIMITER ;

以上DELIMITER告诉命令行工具,使用//做为分隔符。最后一句恢复回;做为分隔符。

2 使用存储过程 CALL

CALL user_pay_total();

以上语句会执行刚才创建的存储过程。

3 删除存储过程 DROP

可以直接使用DROP删除

DROP PROCEDURE user_pay_total;

但是,如果不存在user_pay_total(),就会报错。
所以,建议用以下命令:

DROP PROCEDURE IF EXISTS user_pay_total;

4 使用参数

参数可以用IN, OUT, INOUT修饰。
TODO

5 检测存储过程

以下语句可以显示创建存储过程的鳄鱼局

SHOW CREATE PROCEDURE user_pay_info;

15 触发器

1 创建触发器

  • MySQL触发器只响应以下语句: INSERT, UPDATE, DELETE
  • 保持每个数据库触发器名称唯一。
  • 只有表才支持触发器,视图,临时表不支持。

创建tb1, tb2同tb1

CREATE TABLE `tb1` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '索引值',
  `value` int(11) NOT NULL COMMENT '数据',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

创建触发器,命令行下别忘了 DELIMITER

DELIMITER //

CREATE TRIGGER tb1_cp_tb2
AFTER INSERT ON tb1
FOR EACH ROW
BEGIN
    INSERT INTO tb2(id, value) VALUES (NEW.id, NEW.value);
END //

DELIMITER ;

以上触发器在tb1执行INSERT操作时触发,会给tb2插入相同的数据。

2 删除触发器

DROP TRIGGER IF EXISTS tb1_cp_tb2;

3 触发说明

  • INSERT
    1. INSERT触发器可在INSERT执行之前或之后触发。
    2. 在触发器代码内,可以使用一个名为NEW的虚拟表,访问被插入的行。
    3. 对于AUTO_INCREMENT列,NEW在INSERT之前为0,在INSERT执行之后为自动生成的值。
  • UPDATE
    同INSERT
  • DELETE
    1. DELETE触发器可在DELETE执行之前或之后触发。
    2. 在触发器代码内,可以使用一个名为OLD的虚拟表,访问被插入的行。
      DELIMITER //
      
      CREATE TRIGGER tb1_cp_tb2
      AFTER DELETE ON tb1
      FOR EACH ROW
      BEGIN
          INSERT INTO tb2(id, value) VALUES (OLD.id, OLD.value);
      END //
      
      DELIMITER ;

      从tb1删除的数据会被复制到tb2中。

16 事务处理

事务处理可以用来维护数据库的完整性,保证多个SQL命令要么完全执行,要么完全不执行。

1 事务处理示例

SELECT * FROM tb1;
START TRANSACTION;
DELETE FROM tb1;
SELECT * FROM tb1;
ROLLBACK;
SELECT * FROM tb1;
  • 以上语句中,当删除tb1后,再次查询,没有内容。当回滚后,数据又出现了。
  • 可以使用COMMIT将事务提交上去执行。
  • 不能回退SELECT, CREATE, DROP操作。
  • 当执行COMMIT或ROLLBACK后,事务会自动关闭。

2 保留点

复杂的事务处理中,可能存在需要部分回退或者部分提交的情况。
可以使用保留点来处理。

SAVEPOINT d1; -- 创建了保留点
...
ROLLBACK TO d1;  -- 回滚到保留点

当事务关闭后,保留点会自动释放。

3 autocommit

InnoDB默认 autocommit=on,即每一条sql语句都是当成一个事务,执行后就提交。
当写下START TRANSACTION时,autocommit的设置就无效了。需要等待COMMIT或ROLLBACK来结束事务。
autocommit针对的是每个与MySQL的链接,改变其值不会影响其它链接。

时间: 2024-11-03 04:14:57

MySQL必知必会的相关文章

MYSQL必知必会读书笔记第十和十一章之使用函数处理数据_Mysql

 mysql简介 MySQL是一种开放源代码的关系型数据库管理系统(RDBMS),MySQL数据库系统使用最常用的数据库管理语言--结构化查询语言(SQL)进行数据库管理. 拼接字段 存储在数据库表中的数据一般不是应用程序所需要的格式.我们需要直接从数据库中检索出转换.计算或格式化过的数据:而不是检索出数据,然后再在客户机应用程序或报告程序中重新格式化. 计算字段(字段 = 列,不过数据库列一般称为列,而字段通常用于计算字段中)并不实际存在于数据库表中,计算字段是运行时在select语句内创建的

MYSQL必知必会读书笔记第二章之版本更改_Mysql

MySQL的当前版本为版本5,以下列出最近版本的主要更改: 4.---------InnoDB引擎,增加了事务处理.并.改进全文搜索等支持. 4.1--------对函数库.子查询.集成帮助等重要增加. 5.-------------增加了存储过程.触发器.游标.视图等 以上内容是小编给大家介绍MYSQL必知必会读书笔记的相关知识,希望对大家有所帮助!

MYSQL必知必会读书笔记第三章之显示数据库_Mysql

MySQL是一种开放源代码的关系型数据库管理系统(RDBMS),MySQL数据库系统使用最常用的数据库管理语言--结构化查询语言(SQL)进行数据库管理. show column from tablename: 对每一个字段返回一行,行中包含字段名,数据类型.是否允许NULL.键信息.默认值以及其他信息. describe 语句: MySQL支持使用describ作为show columns from 的一种快捷方式.describ tablename 所支持的其他的show语句: show s

MYSQL必知必会读书笔记第六章之过滤数据_Mysql

mysql简介 MySQL是一种开放源代码的关系型数据库管理系统(RDBMS),MySQL数据库系统使用最常用的数据库管理语言--结构化查询语言(SQL)进行数据库管理. where子句的位置,在同时使用ORDER BY 和WHERE子句时应该让ORDER BY 位于where之后,否则会产生错误. 1.不匹配检查 复制代码 代码如下: SELECT vend_id FROM products where vend_id <>1003 等同于 复制代码 代码如下: SELECT vend_id

MYSQL必知必会读书笔记第四章之检索数据_Mysql

MySQL是一种开放源代码的关系型数据库管理系统(RDBMS),MySQL数据库系统使用最常用的数据库管理语言--结构化查询语言(SQL)进行数据库管理. 使用Select语句返回的数据,可能会发现显示的数据会与其他的地方顺序不同.出现这种情况很正常.如果没有明确排序查询结果.则返回的数据没有特殊意义.返回数据的顺序可能是是数据被添加到表中的顺序,也可能不是.只要返回相同数目的行,就是正常. 注意:SQL语句和大小写 请注意,SQL语句不区分大小写,因此select和SELECT是相同的.同样,

MySQL必知必会之10-14

10.创建计算字段 计算字段并不实际存在于数据库表中.计算字段是运行时在你SELECT语句内创建的. 字段(filed):基本上与列的意思相同,经常互换使用,不过数据库列一般称为列,而术语字段通常用在计算字段的连接上. 10.1拼接字段 拼接:将值联结到一起构成单个值. Concat()函数:多数DBMS使用+或||实现拼接,而MYSQL使用Concat()函数实现. Rtrim()函数:去掉值右边的所有空格 mysql> SELECT CONCAT(RTrim(vend_name),' (',

MySQL必知必会之15-20

15.联结表 SQL最强大的功能之一就是能在数据检索查询的执行中联结表.联结是利用SQL的SELECT能执行的最重要的操作. 关系表的设计是要保证把信息分解成多个表,一类数据一个表,各表通过一定的关系互相关联. 外键:外键为某个表的一列,它包含另一个表的主键值,定义了两个表之间的关系. 可伸缩性:能够适应不断增加的工作量而不失败. 15.1 联结 联结是一种机制,用来在一条select语句中关联表,因此称之为联结.使用特殊的语法,可以联结多个表返回一组输出,联结在运行时关联表中正确的行. 15.

《Oracle PL/SQL必知必会》——第2章 初识Oracle和PL/SQL 2.1 什么是Oracle

第2章 初识Oracle和PL/SQL Oracle PL/SQL必知必会 在本章中,你将认识Oracle和PL/SQL是什么,以及你可以使用什么工具来操作它们. 2.1 什么是Oracle 在前一章中,你学习了数据库和SQL.如所解释的那样,做所有工作(存储.检索.管理和操作数据)的实际上是数据库软件(DBMS或数据库管理系统[Database Management System]).Oracle DBMS(或者简称为Oracle)就是一个DBMS:也就是说,它是数据库软件. Oracle已经

Python 程序员必知必会的开发者工具

Python已经演化出了一个广泛的生态系统,该生态系统能够让Python程序员的生活变得更加简单,减少他们重复造轮的工作.同样的理念也适用于工具开发者的工作,即便他们开发出的工具并没有出现在最终的程序中.本文将介绍Python程序员必知必会的开发者工具. 对于开发者来说,最实用的帮助莫过于帮助他们编写代码文档了.pydoc模块可以根据源代码中的docstrings为任何可导入模块生成格式良好的文档.Python包含了两个测试框架来自动测试代码以及验证代码的正确性:1)doctest模块,该模块可