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.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` ( |
表数据
预期实现目标
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