0. 目标
通过本文可以了解在使用mysql数据库开发时,一些开发技巧。本文比较基础,大神请绕道。
通过本人能够掌握:
- MySQL 行列转换
 - MySQL 列转行
 - MySQL 行转列
 - MySQL 生成唯一序列号
 - MySQL 删除重复数据
 
使用数据及导入方法见MYSQL-SQL开发总结(一)-SQL基础
1. 测试表数据
1  | mysql> SELECT * FROM websites;  | 
1  | mysql> SELECT w.name ,a.count FROM websites w JOIN access_log a ON w.id = a.site_id;  | 
2.行转列场景
欲实现效果,将各个公司网站访问总数统一在一行显示。实现效果如下:
-开发技巧2/markdown-img-paste-2018101615040595.png)
2.1 使用自连接方法实现行转列
思路 我们可以通过单独查询其中一种应用总的访问次数,然后在对几种结果通过cross join 聚合。
- Google 公司网站访问次数总计
 
1  | mysql> SELECT SUM(COUNT) AS 'Google' FROM access_log a JOIN websites w ON w.id = a.site_id AND w.name = 'Google';  | 
- Facebook公司网站访问次数总计
 
1  | mysql> SELECT SUM(COUNT) AS 'Facebook' FROM access_log a JOIN websites w ON w.id = a.site_id AND w.name = 'Facebook';  | 
- 菜鸟教程公司网站访问次数总计
 
1  | mysql> SELECT SUM(COUNT) AS '菜鸟教程' FROM access_log a JOIN websites w ON w.id = a.site_id AND w.name = '菜鸟教程';  | 
- 通过cross join 结果聚合
 
1  | SELECT *  | 
1  | mysql>  | 
缺点: 是将原来查询的结果每一行单独查询出来,再进行拼接。因此每增加一个同学就增加一个SELECT语句。并且是通过交叉连接,要保证每个查询的结果只能是一个,不然没办法通过交叉连接实现转换。
2.2 使用CASE实现行转列
1  | SELECT  | 
3 列转行场景
3.1 单列转多行场景
3.1.1 单列转多行场景实际用途
- (1)属性拆分
 - (2)ETL数据处理
 
3.1.2 单列转多行场景演示-权限拆分
原始数据建表语句及数据
1  | Create Table: CREATE TABLE `user_roles` (  | 
表数据
 -开发技巧2/markdown-img-paste-20181016163536370.png)
预期实现目标
-开发技巧2/markdown-img-paste-20181016170406360.png)
3.1.3 使用序列化表的方法实现行转列
 建立序列表:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20CREATE TABLE  tb_sequence(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY);
INSERT INTO tb_sequence VALUES(),(),(),(),(),(),(),(),();
mysql> SELECT * FROM tb_sequence;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  4 |
|  5 |
|  6 |
|  7 |
|  8 |
|  9 |
+----+
9 rows in set (0.01 sec)
mysql>
最终语句
1  | SELECT b.user_roles_id,b.role_name,  | 
语句解读
- 内部子查询:目的是在 major_roles 每行数据增加一个逗号,在用总长度减去没有逗号的情况时的长度 = size (表示有几个权限,将要转成几行记录)
 
1  | mysql> SELECT user_roles_id,role_name,CONCAT(major_roles,',') AS major_roles,  | 
- 外部查询:外层查询根据序列表 cross join 子查询结果
 
3.2 多列转多行场景
3.2.1 多列转多行场景实际用途
- (1)学生成绩查询
 - (2) ETL 数据抽取
 
3.2.2 多列转多行案例分析-学生成绩行列转换
建表语句及原始数据插入语句
1  | CREATE TABLE `TB_GRADE` (  | 
表中原始数据
1  | mysql> SELECT * FROM TB_GRADE;  | 
预期实现目标
1  | +-----------+-------------+------+  | 
3.2.3 使用UNION方法实现列转行
语句拆分解读
1  | mysql> SELECT user_name,'CN_SCORE' AS '语文',CN_SCORE AS '成绩' FROM TB_GRADE a;  | 
 最终语句 1
2
3
4
5
6
SELECT user_name,'CN_SCORE' AS '学科',CN_SCORE AS '成绩' FROM TB_GRADE a
UNION ALL
SELECT user_name,'MATCH_SCORE' AS '学科',MATCH_SCORE AS '成绩' FROM TB_GRADE a
UNION ALL
SELECT user_name,'EN_SCORE' AS '学科',EN_SCORE AS '成绩' FROM TB_GRADE a;
  最终效果 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21mysql> SELECT user_name,'CN_SCORE' AS '学科',CN_SCORE AS '成绩' FROM TB_GRADE a
    -> UNION ALL
    -> SELECT user_name,'MATCH_SCORE' AS '学科',MATCH_SCORE AS '成绩' FROM TB_GRADE a
    -> UNION ALL
    -> SELECT user_name,'EN_SCORE' AS '学科',EN_SCORE AS '成绩' FROM TB_GRADE a;
+-----------+-------------+------+
| user_name | 学科        | 成绩 |
+-----------+-------------+------+
| 张三      | CN_SCORE    |   58 |
| 李四      | CN_SCORE    |   87 |
| 王五      | CN_SCORE    |   88 |
| 张三      | MATCH_SCORE |   34 |
| 李四      | MATCH_SCORE |   79 |
| 王五      | MATCH_SCORE |   76 |
| 张三      | EN_SCORE    |   72 |
| 李四      | EN_SCORE    |   72 |
| 王五      | EN_SCORE    |   90 |
+-----------+-------------+------+
9 rows in set (0.01 sec)
mysql>
3.2.4 使用序列化表的方法实现列转行
语句拆分解析
- 通过序列固定获取学科
 
1  | mysql> SELECT user_name, CASE WHEN c.id=1 THEN 'CN_SCORE' WHEN c.id=2 THEN 'MATCH_SCORE' WHEN c.id=3 THEN 'EN_SCORE' END AS '学科'  | 
- 通过序列固定获取成绩
 
1  | 
  | 
- 最终查询
 
1  | SELECT user_name, CASE WHEN c.id=1 THEN 'CN_SCORE' WHEN c.id=2 THEN 'MATCH_SCORE' WHEN c.id=3 THEN 'EN_SCORE' END AS '学科',  | 
1  | mysql> SELECT user_name, CASE WHEN c.id=1 THEN 'CN_SCORE' WHEN c.id=2 THEN 'MATCH_SCORE' WHEN c.id=3 THEN 'EN_SCORE' END AS '学科',  | 
4. 生成唯一序列号
4.1 唯一序列号场景及序列号生成方式
需要使用唯一序列号的场景:
作为数据库主键。
业务序列号。
生成序列号的方法:
MySQL:AUTO_INCREMENT
SQLServer:IDENTITY/SEQUENCE
Oracle:SEQUENCE
PgSQL:SEQUENCE
如何选择生成序列号的方式:
【原则】:优先选择系统提供的序列号生成方式。
【优点】:
控制并发;
不重复,保证序列号的唯一性。
【缺点】:序列号不连续(数据空洞),例如 1、2、4。
【原因】:对已有的数据的删除,以及事务回滚等方式不会影响自增长的序号,例如已有数据 1、2、3,删除 3 号数据。之后再插入一条数据,此时数据表的数据为 1、2、4。
4.2 建立特殊需求的序列号
创建订单号,订单序列号格式如下:YYYYMMDDnnnnnnn。如201810170000002
基础表
1  | CREATE TABLE order_seq(  | 
存储过程
1  | DELIMITER //  | 
 结果展示 
此存储过程经测试,每秒中可以生成1千个订单号
1  | mysql> call seq_no();  | 
知识点:
1、在sql语句中添加变量。 declare @local_variable data_type 声明时需要指定变量的类型,可以使用SET、SELECT、SELECT…INTO对变量进行赋值,在sql语句中就可以使用@local_variable来调用变量。
2、RAND()返回一个介于 0 到 1(不包括 0 和 1)之间的伪随机 float 值。
3、事务
4、ROW_COUNT()函数返回查询语句执行后,被影响的列数目
5、IF…THEN…END IF;
5. 删除重复数据
5.1 查询数据是否重复
1  | mysql> SELECT * FROM runoob_tbl;  | 
5.2 删除重复数据,对于相同数据保留ID最大的
sql 语句
1  | DELETE a  | 
效果
1  | mysql> DELETE a  | 
6 希望大家手动敲一遍代码,会收获颇丰!
7 参考
菜鸟教程 http://www.runoob.com/sql/sql-tutorial.html
慕课网sqlercn老师-mysql 开发技巧 https://www.imooc.com/learn/427