
MySQL查询实战:测试工程师的数据探索之旅
MySQL查询实战:测试工程师的数据探索之旅
作为测试工程师,我们经常需要从数据库中查询测试数据、验证数据一致性、分析测试结果。MySQL查询就像是我们的"数据侦探工具",帮我们从海量数据中找到想要的信息。今天就让我们一起掌握这个强大的技能!
环境准备:搭建我们的测试数据库
创建测试数据库
-- 创建一个专门用于测试的数据库
CREATE DATABASE test_automation_db CHARSET=utf8mb4;💡 测试工程师小贴士:
- 使用
utf8mb4字符集,支持emoji等特殊字符 - 为测试项目创建独立的数据库,避免影响生产环境
创建测试数据表
-- 使用测试数据库
USE test_automation_db;
-- 确认当前使用的数据库
SELECT DATABASE();
-- 创建用户测试表(模拟测试用户数据)
CREATE TABLE test_users(
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT NOT NULL,
username VARCHAR(50) DEFAULT '',
age TINYINT UNSIGNED DEFAULT 0,
height DECIMAL(5,2),
gender ENUM('男','女','其他','保密') DEFAULT '保密',
department_id INT UNSIGNED DEFAULT 0,
is_active BIT DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 创建部门表(模拟测试环境配置)
CREATE TABLE departments (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
name VARCHAR(50) NOT NULL,
description TEXT
);
-- 插入测试数据
INSERT INTO departments (name, description) VALUES
('测试部', '负责产品质量保证'),
('开发部', '负责产品功能开发'),
('运维部', '负责系统运维保障');
INSERT INTO test_users (username, age, height, gender, department_id) VALUES
('测试工程师张三', 28, 175.5, '男', 1),
('测试工程师李四', 26, 162.0, '女', 1),
('开发工程师王五', 30, 180.0, '男', 2),
('运维工程师赵六', 32, 170.0, '女', 3);🎯 测试场景说明: 这些表结构模拟了真实的测试环境,我们可以用它们来练习各种查询技巧。
查
查询所有字段
查询指定字段
使用as给字段起名字
使用as给表起别名
-- 查询所有字段
-- select * from 表名;
select * from students;
select * from classes;
select id, name from classes;
-- 查询指定字段
-- select 列1,列2,... from 表名;
select name, age from students;
-- 使用 as 给字段起别名
-- select 字段 as 名字.... from 表名;
select name as 姓名, age as 年龄 from students;
-- select 表名.字段 .... from 表名;
select students.name, students.age from students;-- 可以通过 as 给表起别名
-- select 别名.字段 .... from 表名 as 别名;
select students.name, students.age from students;
select s.name, s.age from students as s;
-- 失败的select students.name, students.age from students as s;消除重复行
distinct 字段;
select distinct gender from students;
-- 这个功能可以用group by功能抵消,一般不用
select 字段 from 表 group by 字段;条件查询
比较运算符
select 字段 from 表 where 字段 >/=/< 条件;逻辑运算符 and or not
select 字段 from 表 where 字段 =条件 and 字段2 = 条件;模糊查询 放在where后面使用
like %代表一个或者多个或者没有 _代表一个
rlike "^周.*伦$"以什么开始以什么结尾
like和rlike在这里面都翻译为像的意思代替的是条件中的=
-- 查询姓名中 以 "小" 开始的名字
select name from students where name="小";
select name from students where name like "小%";
-- 查询姓名中 有 "小" 所有的名字
select name from students where name like "%小%";
-- 查询有2个字的名字
select name from students where name like "__";
-- 查询有3个字的名字
select name from students where name like "__";
-- 查询至少有2个字的名字
select name from students where name like "__%";范围查询
非连续范围: in(),not in()
where 字段 in ();
连续范围:between...and...,not between ... and...
where 字段 between ... and ...;
-- in (1, 3, 8)表示在一个非连续的范围内
-- 查询 年龄为18、34的姓名
select name,age from students where age=18 or age=34;
select name,age from students where age=18 or age=34 or age=12;
select name,age from students where age in (12, 18, 34); -- not in 不非连续的范围之内
-- 年龄不是 18、34岁之间的信息
select name,age from students where age not in (12, 18, 34); -- between ... and ...表示在一个连续的范围内
-- 查询 年龄在18到34之间的的信息
select name, age from students where age between 18 and 34; -- not between ... and ...表示不在一个连续的范围内
-- 查询 年龄不在在18到34之间的的信息
select * from students where age not between 18 and 34;
select * from students where not age between 18 and 34;
-- 失败的select * from students where age not (between 18 and 34);空判断
null
not null
-- 判空is null
-- 查询身高为空的信息
select * from students where height is null;
select * from students where height is NULL;
select * from students where height is Null; -- 判非空is not null
select * from students where height is not null;排序
-- order by 字段 asc/desc
-- asc从小到大排列,即升序
-- desc从大到小排序,即降序
多个排序 order by 字段 asc/desc,字段 asc/desc,...;
-- 查询年龄在18到34岁之间的男性,按照年龄从小到到排序
select * from students where (age between 18 and 34) and gender=1;
select * from students where (age between 18 and 34) and gender=1 order by age;
select * from students where (age between 18 and 34) and gender=1 order by age asc;-- 查询年龄在18到34岁之间的女性,身高从高到矮排序
select * from students where (age between 18 and 34) and gender=2 order by height desc;-- order by 多个字段
-- 查询年龄在18到34岁之间的女性,身高从高到矮排序, 如果身高相同的情况下按照年龄从小到大排序
select * from students where (age between 18 and 34) and gender=2 order by height desc,id desc;-- 查询年龄在18到34岁之间的女性,身高从高到矮排序, 如果身高相同的情况下按照年龄从小到大排序,
-- 如果年龄也相同那么按照id从大到小排序
select * from students where (age between 18 and 34) and gender=2 order by height desc,age asc,id desc;-- 按照年龄从小到大、身高从高到矮的排序
select * from students order by age asc, height desc;聚合函数
所谓的聚合函数其实就是对字段的统计分析
主要分为max count max min avg round(a,3)保留三位小数等
select count(*) from students where age =25;
-- 总数
-- count
-- 查询男性有多少人,女性有多少人
select * from students where gender=1;
select count(*) from students where gender=1;
select count(*) as 男性人数 from students where gender=1;
select count(*) as 女性人数 from students where gender=2;
-- 最大值
-- max
-- 查询最大的年龄
select age from students;
select max(age) from students;
-- 查询女性的最高 身高
select max(height) from students where gender=2;
-- 最小值
-- min
-- 求和
-- sum
-- 计算所有人的年龄总和
select sum(age) from students;
-- 平均值
-- avg
-- 计算平均年龄
select avg(age) from students;
-- 计算平均年龄 sum(age)/count(*)
select sum(age)/count(*) from students;
-- 四舍五入 round(123.23 , 1) 保留1位小数
-- 计算所有人的平均年龄,保留2位小数
select round(sum(age)/count(*), 2) from students;
select round(sum(age)/count(*), 3) from students;
-- 计算男性的平均身高 保留2位小数
select round(avg(height), 2) from students where gender=1;
-- select name, round(avg(height), 2) from students where gender=1;分组
--group by 字段
例如select gender,count(*) from students where gender=1` group by gender;
其实是先把students按gender分组,分成男生女生,然后分别统计男生、女生的gender,总数。
--其实分组要和聚合函数在一起才能体现出他的价值
-- 失败select * from students group by gender;
为什么这一条命令会失败呢?请注意,你是给gender进行分组,那么每个gender里面包含很多信息,是用每个gender表达不出来的。
group by的图可以用如下来解释
其实,分组可以这么理解,对分组后的函数使用聚合函数
group by的前面还可以使用where进行条件筛选,也就是先把表按条件查询,之后再分组:详细见sql练习题36,练习题12
group by也是可以多个分组的,即group by a.ddc=b.aas,a.das=b.sda
select 字段 聚合函数 from 表 group by 字段;
-- 按照性别分组,查询所有的性别
select name from students group by gender;
select * from students group by gender;
select gender from students group by gender;
-- 失败select * from students group by gender;
-- 计算每种性别中的人数
select gender,count(*) from students group by gender;
-- 计算男性的人数
select gender,count(*) from students where gender=1 group by gender;
-- group_concat(...)
-- 查询同种性别中的姓名
select gender,group_concat(name) from students where gender=1 group by gender;
select gender,group_concat(name, age, id) from students where gender=1 group by gender;
select gender,group_concat(name, "_", age, " ", id) from students where gender=1 group by gender;
-- having
-- 查询平均年龄超过30岁的性别,以及姓名 having avg(age) > 30
select gender, group_concat(name),avg(age) from students group by gender having avg(age)>30;
-- 查询每种性别中的人数多于2个的信息
select gender, group_concat(name) from students group by gender having count(*)>2;-- group_concat(...)
主要用于显示分组后,该组成员的信息
用法:group_concat(name, "_", age, " ", id)
having
用于对结果的分析,一般前面有group by
分页
limit start, count
注意这个语句一般是放在最后面的
count代表要显示的个数,start代表要从第几个开始、默认值为0 可以省略
这里面有一个公式limit a=(第N页-1)*每个的个数, b=每页的个数;
==?== --limit前面加asc后的影响
select * from students order by age asc limit 10,2;
select * from students where gender=2 order by height desc limit 0,2;连接查询--用于两个表的连接
一般使用内连接和左连接
链接说白了就是把两个或者多个表左右拼接到一起,按照on后面所匹配的字段,当然根据inner 和left join 的不同,所显示的内容是不同的
内链接取交集
左链接取左并集,也就是说左链接是以左面的表为准,在另一个表中,如果相关就显示,如果不相关就空着(左面的表的数据都会有,右面的表能匹配到就有值,没有就是null)
这里面还有一点要注意的是on的用法,on后面所匹配的字段可以用and的连接,也就是多字段匹配。on(a.cad=b.dfa and a.khh=b.jjh)
on后面不仅可以加等号的匹配还有用不等号限定区间来匹配,例如:面试题18题告诉了我一个知识点
关于联结与where的顺序问题,where一般放在联结之后进行筛选,详细见sql练习题45
inner join ... on
left join ... on
select ... from 表A inner join 表B on 匹配信息;
可以用as将表进行别用名
select c.name, s.* from students as s inner join classes as c on s.cls_id=c.id;
-- select ... from 表A inner join 表B;
select * from students inner join classes;
-- 查询 有能够对应班级的学生以及班级信息
select * from students inner join classes on students.cls_id=classes.id;
-- 按照要求显示姓名、班级
select students.*, classes.name from students inner join classes on students.cls_id=classes.id;
select students.name, classes.name from students inner join classes on students.cls_id=classes.id;
-- 给数据表起名字
select s.name, c.name from students as s inner join classes as c on s.cls_id=c.id;
-- 查询 有能够对应班级的学生以及班级信息,显示学生的所有信息,只显示班级名称
select s.*, c.name from students as s inner join classes as c on s.cls_id=c.id;
-- 在以上的查询中,将班级姓名显示在第1列
select c.name, s.* from students as s inner join classes as c on s.cls_id=c.id;
-- 查询 有能够对应班级的学生以及班级信息, 按照班级进行排序
-- select c.xxx s.xxx from student as s inner join clssses as c on .... order by ....;
select c.name, s.* from students as s inner join classes as c on s.cls_id=c.id order by c.name;
-- 当时同一个班级的时候,按照学生的id进行从小到大排序
select c.name, s.* from students as s inner join classes as c on s.cls_id=c.id order by c.name,s.id;
-- left join
-- 查询每位学生对应的班级信息
select * from students as s left join classes as c on s.cls_id=c.id;
-- 查询没有对应班级信息的学生
-- select ... from xxx as s left join xxx as c on..... where .....
-- select ... from xxx as s left join xxx as c on..... having .....
select * from students as s left join classes as c on s.cls_id=c.id having c.id is null;
select * from students as s left join classes as c on s.cls_id=c.id where c.id is null;多联结
select a.*,b.* ,c.*
from
(select * from world.city) a
inner join
(select * from world.country) b
on a.CountryCode=b.Code
inner join
(select * from world.countrylanguage) c
on c.CountryCode=b.Code
-- 在多几个连接表也是这样的就是inner join(联结一个表)_____on(在什么相同的列上联结)自关联
把具有相同结构或者性质的表写成一个表,这时候表的结构变得简单,但是内容变得复杂了
将多个表变成一个表
-- 查询所有省份
select * from areas where pid is null;
-- 查询出山东省有哪些市
select * from areas as province inner join areas as city on city.pid=province.aid having province.atitle="山东省";
select province.atitle, city.atitle from areas as province inner join areas as city on city.pid=province.aid having province.atitle="山东省";
-- 查询出青岛市有哪些县城
select province.atitle, city.atitle from areas as province inner join areas as city on city.pid=province.aid having province.atitle="青岛市";
select * from areas where pid=(select aid from areas where atitle="青岛市")
-- 相当于一个表当成两个表来用,脑补,一个表变成两个表,相同字段匹配链接。子查询
子查询就是select语句中嵌套另外一个语句,把其当做条件去查询
degreee < avg(degree) 对于这种查询是不能用的,你的意思查询的分数要低于平均分,但是在sql中是不认同这种写法的,正确的做法是 degree < (sql语句表示平均分,例如 select avg(degree) from score )
-- 查询最高的男生信息
select * from students where height = 188;
select * from students where height = (select max(height) from students);
-- 列级子查询
-- 查询学生的班级号能够对应的学生信息
-- select * from students where cls_id in (select id from classes);数据的查询,在整个sql中是最重要的部分,也是工作中经常使用的地方。
- 说一下查询的总体思路,一般提取数据的时候,根据要提取的数据抽象成一个问题。
例如:看这样一道题。
查询score表中选学一门以上课程(cno)的同学(sno)中分数为非最高分成绩(degrees)的记录。
这个问题分成两个条件,第一个条件是选学一门以上,第二个条件是非最高成绩,两个问题之间用and来链接
当然,对于条件,要区分是where下面的条件还是需要分组group by后的having
要提取的数据是什么呢,没有说,那就是所有数据,那个表呢,是score表
根据上面思路进行整体可以写下如下句子
select * from score where xxxx and xxxx;进一步明确各个条件,第一个,选学一门以上,限定的是课程con,一门以上就是对其进行统计group by
第二个条件,非最高课程,限定的是degree,非最高就是not in 最高
最后一步就是整合了
- 一般的查询是在语句后面加入where,但是常用的查询中会混入条件(比较、逻辑、模糊、范围)的查询(注意括号的使用,很多语言(Python,Java...)都是会先计算括号里面的值的)
- 在查询中也可能根据字段进行排序order by(asc\desc)
- 查询也会进行一些统计分析,这就涵盖了一些聚合函数的使用,这个过程中你也可能用到分组(group by)进行个别字段统计,当然对分组后的结果进行筛选,就是having的运用了
聚合函数其实也可以和子查询进行操作,这时候,主要是用到范围的操作 in,进行条件筛选的判断。 - 取数据也可能进行分页的选取,这个时候你就要会limit函数的运用
- 多个表的查询,对其中相同字段的统计,常见用左联结和內联结(left jion / inner jion)
- 将多份结构相同的表放在一起,这样会增加表的复杂度,但是比较清晰,自关联就可以实现这个表的查询,当然自关联还可以把一个表当做多个表对待(使用as重命名操作)
下面是对一些重要语句的整理
select 字段 as 新名字, 字段 as 新名字 from 表 where 字段=/</>/and/or/like/rlike 条件;
-- 模糊
% _ "^周.*伦$"
-- 范围
select 字段 ,字段 from 表 字段 in (1,2,7);%非连续型
select 字段 ,字段 from 表 字段 between 2 and 6;
select 字段 ,字段 from 表 字段 is not null;
-- 多字段排序
select * from students order by age asc, height desc;
-- 聚合函数与分组函数
select gender,count(*) from students where gender=1 group by gender;
-- 分页 limit (第N页-1)*每个的个数, 每页的个数
select * from students limit 6,2;
-- 连接查询
select c.name, s.* from students as s inner join classes as c on s.cls_id=c.id order by c.name;
-- 子查询
select * from students where cls_id in (select id from classes);