Mysql之DQL,各种查查查

Posted 阿西巴&阿力鸡

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mysql之DQL,各种查查查相关的知识,希望对你有一定的参考价值。

一、DQL

DQL 主要指查询语句,有查询单表数据,也有查多表数据表,本次主要是单表查询

  • 基本查询

  • 条件查询

  • 模糊查询

  • 排序查询

  • 聚合查询

  • 去重查询

  • 分组查询

  • 限制查询

1.1 数据准备

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for stu
-- ----------------------------
DROP TABLE IF EXISTS `stu`;
CREATE TABLE `stu` (
  `sid` int(11) DEFAULT NULL,
  `sname` varchar(25) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `sex` char(6) DEFAULT NULL,
  `score` int(11) DEFAULT NULL,
  `cid` int(11) DEFAULT NULL,
  `groupLeaderId` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of stu
-- ----------------------------
INSERT INTO `stu` VALUES (1001, '张三', '20', '男', '72', '1', '1003');
INSERT INTO `stu` VALUES (1002, '李四', '15', '女', '78', '1', '1003');
INSERT INTO `stu` VALUES (1003, '王五', '95', '男', '99', '1', '1010');
INSERT INTO `stu` VALUES (1004, '赵六张', '65', '女', '60', '1', '1007');
INSERT INTO `stu` VALUES (1005, '周七', '55', '男', '78', '3', '1007');
INSERT INTO `stu` VALUES (1006, '茅十八', '75', '女', '96', '3', '1007');
INSERT INTO `stu` VALUES (1007, '张三丰', '40', '男', '85', '3', '1010');
INSERT INTO `stu` VALUES (1008, '李四方', '45', '女', '90', '2', '1010');
INSERT INTO `stu` VALUES (1009, '艾三弗森', '45', '', '35', '4', '1008');
INSERT INTO `stu` VALUES (1010, '三欧文', '35', '女', '49', '2', '1008');

1.2 基本查询

select 字段1,字段2,... from 表名;

查询返回的是一张虚拟表,查询对原表数据没有任何影响,默认查询的全表数据

/*基本查询
    查询所有列
    查询指定 列
    
    select xxx from  表名 
    [where x = x ]
    [group by 字段]
    [having 表达式]
    [order by asc|desc]
    [limit [x,y]]
*/
select sid,sname,age,sex,score,cid,groupLeaderId from stu;
select cid,sid,sname,age,sex,score,groupLeaderId from stu;
-- 真正生产环境中不能写*,要把字段全部写出来,因为性能不好
select * from stu;
-- 查询学生学号、姓名和今年年龄以及明年年龄
select sid,sname,age,age+1 as '明年' from stu;
-- 查询所有列
select sid,sname,age,sex,score,cid groupLeaderId from stu;
-- 查询所有列,在测试,练习时可以使用*代替
select * from stu;
-- 查询指定 列
select sid,sname,sex from stu;
-- 年龄+1
select age+1 from stu;

算数运算符

描述

+

两列做加法运算

-

两列做减法运算

*

两列做乘法运算

/

两列做除法运算

注意:%是占位符,而非模运算符。

1.3 条件查询

条件查询就是在基础查询基础上,再给sql设置条件,只查询部分符合条件的数据

条件语句 : select 字段1,字段2,... from 表名 where 字段 条件 值;

条件运算符

  • =

  • >

  • <

  • >=

  • <=

  • !=

  • and

  • or

  • in

  • not in

  • between..and

/*================条件查询===================
select 字段,... from 表 where 字段 条件 值;
条件: =,!=,>,<.>=,<=,and,or,between and,in,is null,is not null
查询效果:符合条件的数据保留
    */
--     查询学号为1001的学生信息
select * from stu where sid = 1001;

-- 查询学生成绩大于60的学生id 姓名,成绩
select sid,sname,score from stu where score > 60;

-- 查询学生性别为女,并且年龄小于50的记录
select * from stu where sex = '女' and age < 50;

-- 查询学生学号为1001,或者姓名为李四的记录
select * from stu where sid = 1001 or sname = '李四';

-- 查询学号为1001,1002,1003的记录
select * from stu where sid >= 1001 and sid <= 1003;
select * from stu where sid in(1001,1002,1003);
select * from stu where sid in(1001,1002,1003,1111); -- 没有1111,也可以查出来

-- 查询学号不是1001,1002,1003的记录
select * from stu where sid != 1001 and sid != 1002 and sid != 1003;
select * from stu where sid not in(1001,1002,1003);

-- 查询学生年龄在20到40之间的学生记录
select * from stu where age >= 20 and age <= 40; 
select * from stu where age between 20 and 40;

-- 查询性别非男的学生记录
select * from stu where sex != '男';
select * from stu where sex = '女';

-- 查询性别为空的性别
update stu set sex = null where sid = 1009;
select * from stu where sex is null;    -- 查询时不能用 sex = null

-- 查询性别不为空的性别
select * from stu where sex is not null;

1.4 模糊查询

模糊查询其实也是条件查询

语法: select 字段1,字段2,... from 表名 where 字段 like '_值%';

  • _ 匹配任意一个字符

  • % 匹配任意多个字符

/*====================模糊查询================
 select 字段1,字段2,... from 表名 where `字段 like '_值%'`;
 _  匹配任意一个字符
 % 匹配任意多个字符
*/
-- 查询姓名以“张”开头的学生记录
select * from stu where sname like '张%';

-- 查询姓名中包含“三”的学生记录
select * from stu where sname like '%三%';

1.5 排序查询

对查询后的数据按照指定字段以及指定规则排序

语法: select 字段1,字段2,... from 表名 order by 字段 [desc|asc];

  • desc 降序 descend

  • asc 升序,默认是升序 ascend

排序查询写在最后

/*========================排序查询=======================
 where order by asc|desc   (ascend 升序|descend 降序) 默认升序
*/
-- 查询所有学生记录,按年龄升序排序
select * from stu order by age asc;

-- 查询所有学生记录,按年龄降序排序
select * from stu order by age desc;

-- 查询所有学生记录,按年龄升序排序,如果年龄相同时,按编号降序排序
select * from stu order by age asc ,sid desc;

-- 查询成绩大于60的学生id,姓名,成绩,并根据成绩降序
select sid,sname,score from stu

where score > 60 
order by score desc; 

1.6 聚合函数

将查询的结果,聚合运算得到一个结果值,语法特点:

  • 聚合运算完,结果只有一行数据

  • 其他字段不能和聚合函数同时查询,除非有分组查询

聚合函数分类:

  1. count(expr) 计算指定列的不为null的行数

  1. max(expr) 计算指定列的最大值

  1. min(expr) 计算指定列的最小值

  1. avg(expr) 计算指定列的平均数,除以不为null的条数

  1. sum(expr) 计算指定列的和 ,计算不为null的数据

函数中的expr,可以写列名,也可以写函数表达式

语法: select 聚合函数(字段) from 表名;

/*================聚合函数=============
*/
-- 查询stu表中记录数:
select count(sid) from stu;

-- 查询stu表中有性别的人数:
select count(sex) from stu;

-- 查询stu表中成绩大于60的人数:
select count(sid) from stu where score > 60;

-- 查询所有学生成绩和:
select sum(score) from stu;

-- 统计所有学生平均成绩
select avg(score) from stu;  -- 有问题,不会管空成绩的
select sum(score)/count(sid) from stu;

-- 查询最高成绩和最低成绩:  
select min(score),max(score) from stu;
-- 查询可以给列取别名, 用as
select min(score) as '最小值',max(score) as '最大值'from stu;
-- 可以不写as ,甚至不写单引号都行
select min(score) '最小值' ,max(score) 最大值 from stu;
select min(score) 最小值 ,max(score) 最大值 from stu;

1.7 去重函数

可以将某列数据去重查询,distinct,一般不单独使用,配合聚合函数使用

-- ============== 去重查询 ============== 
-- 查询年龄不重复的共有多少人        
select count(distinct age) from stu;
select distinct age from stu;

1.8 分组查询

分组查询,就是将查询的数据分为几组.

语法: select 字段1,字段2,... from 表名 [where 字段 条件 值] group by 字段 having 字段 条件值;

group by 字段,根据指定字段分组

having 字段 值, 分组后再过滤

有个非常重要特点: SQL只要有分组, 分成几组,查询结果就只有几行 ,所以一般 配合聚合函数来使用

!!!!!! 与 聚合函数 同时出现的 列,必须 出现在group by 语句中 !!!!!!

或者说group by后面的字段可以出现在select后

再或者说,sql语句中有group by,那么前面select后的字段,要么是group by字段,要么就是聚合函数

having和where都是过滤

where是分组前过滤,having是分组后过滤

where后不能使用聚合函数,having可以聚合函数

/*==============分组查询============
    select 聚合函数/分组字段 from 表 [where] group by 字段
    */
-- 查询男生多少人,女生多少人
select sex,count(sid) from stu group by sex;

-- 查询每个班级的班级编号和每个班级的成绩和:
select cid,sum(score) 总分 from stu group by cid;
select cid,sum(score) 总分 from stu group by cid order by cid asc;
-- 查询每个班级的班级编号和每个班级的平均成绩:
select cid,avg(score) 平均分 from stu group by cid;
select cid,sum(score)/count(cid) 平均分 from stu group by cid;

-- 查询每个班级的班级编号以及每个班级的人数:
select cid,count(sid) 人数 from stu group by cid;

-- 查询每个班级的班级编号以及每个班级的男女人数:
select cid,sex,count(sid) 人数 from stu group by cid,sex;

-- 查询成绩总和大于200的班级编号以及成绩和:(分组后过滤数据用having)
select cid,sum(score) 总分 from stu group by cid having sum(score) > 200;

-- 查询每个班成绩大于60的人数
select cid,count(sid) from stu where score > 60 group by cid ;

-- 查询 所有人 成绩都大于50的班级的班级号和人数(先分组再过滤,只要最低的大于50就可以留下)
select cid,count(sid) from stu group by cid having min(score) > 50;

-- 查询成绩总和大于200的班级编号以及成绩和并根据成绩总和升序
select cid,sum(score) from stu 
group by cid 
having sum(score) > 200
order by sum(score) asc;
-- 使用别名来写(sum(score) he)
select cid,sum(score) he
from stu
group by cid
having he > 20
order by he asc;

1.9 限制查询

就是将查询完的数据,可以限制展现条数

语法: limit n -- 限制输出指定n条,从第一条开始

limit x,y -- 限制输出,从x下标处输出y条,第一条的下标是0

常用于分页操作

-- 限制(limit)查询
/*==========分页(limit)查询==============
  在最后面放上limit x [,y] (中括号意思是可写可不写)
*/
select * from stu limit 5;
-- 限制从 x 处输出 y 条,x从0开始
select * from stu limit 0,4;
select * from stu limit 2,4;

分页

-- 分页中有些已知条件
-- 当前页    pageNo = 1
-- 每页数据量pageSize = 3
-- 数据总量  total = count(sid)
-- 页数      pageCount = total % pageSize == 0 ? total / pageSize : (total / pageSize) + 1
-- 第一页
select * from stu limit 0,3;
-- 第二页
select * from stu limit 3,3;
-- 第三页
select * from stu limit 6,3;
-- 第pageNo页
select * from stu limit (pageNo - 1)*pageSize,pageSize;

二、顺序

2.1 书写顺序

select * 
from 表名 
where 条件 
group by 字段 
having 条件 
order by 
limit x,y

------
select cid,sum(score) from stu
where sid >= 1002
group by cid
having sum(score) > 100
order by sum(score) desc
limit 1

2.2 执行顺序

from   获得全部数据
where  过滤一部分数据
group by 分组
having   过滤分组后的数据
select  查询展现数据,这里 有聚合的话在 此时聚合
order   排序
limit   限制

三、多表联查

3.1 表之间的关系

表和表的关系有:

  • 一对一 老公 --> 老婆 , 人 ---> 身份证/户口本

  • 一对多 一只手 --> 五根指头 , 人 ---> 房/车

  • 多对多 订单 --> 商品

3.2 合并结果集

合并结果集,是将多表查询的结果纵向合并

语法:

select field1,field2 from t1

union -- 合并结果集

select field1,field2 from t2

create table tb_a(
 id int,
 name char(10),
 age int
);

create table tb_b(
 id int,
 name char(10)
);
/*
 合并结果集的两个表的字段
 数量,类型要一致
-----------
union 联合数据,将数据纵向拼接,如果有 重复数据会 去重
union all 如果有 重复数据会 全部保留
--------------
场景:
当表很大时,可以拆分成多个表
就可以使用联合查询
*/
select id,name from tb_a
union all
select id,name from tb_b

3.3 连接查询【重要】

连接查询是将多张表数据连接在一起(横向)查询返回,

这个连接是多表的乘积,t1 * t2 , 这就是笛卡尔积

连接查询需要使用表之间的 关联关系来过滤数据(去除笛卡尔积

连接查询分为以下几种

  • 内连接 inner join

  • 外连接 outer join

表:

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for class
-- ----------------------------
DROP TABLE IF EXISTS `class`;
CREATE TABLE `class` (
  `cid` int(11) DEFAULT NULL,
  `cname` varchar(255) COLLATE utf8_bin NOT NULL,
  `caddress` varchar(255) COLLATE utf8_bin DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

-- ----------------------------
-- Records of class
-- ----------------------------
INSERT INTO `class` VALUES ('1', 'BigData', '102');
INSERT INTO `class` VALUES ('2', 'html', '103');
INSERT INTO `class` VALUES ('3', 'VR', '104');
INSERT INTO `class` VALUES ('4', 'Java', '105');

3.3.1 内连接

数据准备, class表是班级表,stu是学生表, 一个班级对应多个学生

两表的关联列是 学生表(stu)中的cid,引用了班级表(class)中的主键cid

语法:

select 字段列表 from 表1 inner join 表2 on 表1.字段 = 表2.字段

/*
 内连接
 select 字段列表 from 表1 inner join 表2 on 表1.字段 = 表2.字段
*/
-- 查询学生信息以及学生关联的班级信息
select * from stu inner join class on stu.cid = class.cid;
-- 查询学生的学号,姓名,分数,班号,班名
select stu.sid,stu.sname,stu.score,stu.cid,class.cname 
from stu 
inner join class 
on stu.cid = class.cid;
-- 也可以给表设置别名
select s.sid,s.sname,s.score,s.cid,c.cname 
from stu s
inner join class c
on s.cid = c.cid;
-- 内连接特点:只会查询满足关联条件的数据

-- 内连接标准写法
select * from stu inner join class on stu.cid = class.cid;
-- 内连接可以简写成(推荐)
select * from stu s,class c where s.cid = c.cid;

-- 标准语法
-- 简写
-- 特点
-- 什么叫笛卡尔积
-- 去除笛卡尔积  加上查询条件 (on x = x   或者  where x = x)

-- ============内连接============  inner join ... on
select * from stu inner join class on stu.cid = class.cid;
select * from stu s inner join class c on s.cid = c.cid;  -- 使用别名
-- 以上是标准语法,mysql有简化写法
select * from stu,class where stu.cid = class.cid;
select * from stu s,class c where s.cid = c.cid;   -- 使用别名
-- 内连接只会保留完全符合关联条件的数据

练习:

-- 查询1班信息,以及对应学生信息
select * from class c,stu s where c.cid = s.cid and c.cid = 1;
-- 查询成绩大于60的学生信息,以及对应的专业
select * from stu s,class c where s.cid = c.cid and score > 60;
-- 查询班级编号,班级名称,和每班人数
select c.cid,c.cname,count(sid) from class c,stu s 
where c.cid = s.cid
group by c.cid,c.cname

3.3.2 外连接

外连接又分为左外连接,右外连接

语法:

select 字段列表 from 表1 left|right outer join 表2 on 表1.字段 = 表2.字段

3.3.3内外连接有什么区别?

  • 内连接只查询符合关联添加的数据

  • 外连接会保留不符合条件的数据

eg: 先给stu表加一个 没有 cid 的项

select * from stu s          -- 保留了没有cid的项,而内连接没有保留
left outer join class c
on s.cid = c.cid; 

select * from stu s
right outer join class c
on s.cid = c.cid;   

select * from stu s
inner join class c
on s.cid = c.cid;   
-- 1) 外连接会保留不符合条件的数据
-- 2) 左外是以左表为主,左表中有不符合条件的数据也会保留
--    右外相反...

-- 查询学生信息以及对应的班级信息
-- 左外
select * from stu s left outer join class c on s.cid = c.cid

-- 右外
select * from stu s right outer join class c on s.cid = c.cid

-- outer可以省略
select * from stu s left join class c on s.cid = c.cid
-- 查询学生信息和学生对应班级信息(即使学生没有班级)
select * from stu s
left outer join class c
on s.cid = c.cid;   
-- 结果含没有班级的学生(左外连接,会保留左表里面不符合条件的数据)

select * from stu s
right outer join class c
on s.cid = c.cid;
-- 结果不含没有班级的学生(右外连接,会保留右表里面不符合条件的数据)

-- 查询1班信息,以及对应学生信息
select *
from class 
left join stu 
on stu.cid = class.cid 
where class.cid = 1;

-- 查询成绩大于60的学生信息,以及对应的专业
select s.*,c.cname
from stu s
left join class c
on s.cid = c.cid
where s.score > 60;

-- 查询班级编号,班级名称,和每班人数
select c.cid,c.cname,count(s.sid)
from class c
left join stu s
on c.cid = s.cid
group by c.cid,c.cname;

3.4 子查询【重要】

子查询(subquery)也叫嵌套查询

  • 将sql语句当表,写在from后面

  • 将sql语句当条件,写在where后面

-- ==========子查询===========
-- 嵌套查询,讲一个sql语句套在另一个sql语句里面
-- 套在sql语句from后面当表用
-- 套在sql语句where后面当条件的值

-- 查询与张三同一个班级的学生。
select * from stu 
where cid = (
select cid from stu 
where sname = '张三'
);

-- 成绩高于3号班级所有人的学生信息
select * 
from stu 
where score > (
select max(score) from stu where cid = 3
)

-- 子查询当表用(查出来的信息时虚拟表)
select * 
from(select * from stu where score > 60) t
where t.age > 30;

-- 有2个以上直接组员的 学生信息
select groupLeaderId,count(groupLeaderId) 
from stu 
group by groupLeaderId
having count(groupLeaderId) > 2;

select * from stu where sid in(
select groupLeaderId
from stu 
group by groupLeaderId
having count(groupLeaderId) > 2
)

-- 求1008学生编号、姓名、组长编号和组长姓名
select s1.sid ,s1.sname,s2.sid,s2.sname from stu s1 , (
select sid,sname from stu where sid = (
select groupLeaderId from stu where sid = 1008))s2
where s1.sid = 1008 ;
-- 可以 自连接 查询
select s.sid,s.sname,z.sid,z.sname 
from stu s,stu z
where s.sid = 1008
and s.groupLeaderId = z.sid;

-- 查询 每个学生成绩大于等于60 且 成绩总和大于200 的 班级编号 以及 成绩和 并根据 成绩和 升序 

select cid,sum(score)  
from stu
group by cid  
having sum(score)>200 and min(score) >= 60  
order by sum(score) asc;

以上是关于Mysql之DQL,各种查查查的主要内容,如果未能解决你的问题,请参考以下文章

MySQL的DQL语言(查)

MySQL 之基础操作及增删改查等

MySql学习笔记之DQL常用查询

MySQL之DQL——查询语言

MySQL语句使用。

No.8 MySQL数据库之实战演练:各种增删改查