DQL数据查询 -- 单表查询

131 阅读8分钟

一、DQL-介绍

DQL英文全称是Data Query Language(数据查询语言),数据查询语言,用来查询数据库中表的记
录。
查询关键字:**SELECT
**在一个正常的业务系统中,查询操作的频次是要远高于增删改的,当我们去访问企业官网、电商网站,
在这些网站中我们所看到的数据,实际都是需要从数据库中查询并展示的。而且在查询的过程中,可能
还会涉及到条件、排序、分页等操作。

数据查询语言需要重点掌握!!!

数据查询语言需要重点掌握!!!

数据查询语言需要重点掌握!!!

二、DQL语法

SELECT
	字段列表
FROM
	表名列表
WHERE
	条件列表
GROUP BY
	分组字段列表
HAVING
	分组后条件列表
ORDER BY
	排序字段列表
LIMIT
	分页参数
  • 基本查询

  • 条件查询(WHERE)

  • 聚合查询(count、max、min、avg、sum)

  • 分组查询(GROUP BY)

  • 排序查询(ORDER BY)

  • 分页查询(LIMIT)

where 和 having的区别:
执行时机不同: where是分组之前进行过滤,不满足where条件,不参与分组;而having是分组之后对结果进行过滤。
判断条件不同: where不能对聚合函数进行判断,而having可以。

having:不能单独使用,不能代替where,必须和group by联合使用

优化策略:wherehaving ,优先选择 wherewhere 实在完成不了了,在使用 having

聚合函数 -------null值不参与所有聚合函数运算
select 聚合函数(字段列表) from 表名;
count:统计数量;
max:最大值;
min:最小值;
avg:平均值;
sum:求和;

分组查询
分组之后,查询的字段一般为聚合函数和分组字段,查询其他字段无任何意义

排序查询 order by

支持多个字段排序,先按第一个字段排序,若第一个字段相同,则按第二个字段,以此类推,之间用逗号隔开。有:

asc:升序(默认值);

desc:降序

分页查询 limit

1.起始索引从0开始,起始索引 = (查询页码 - 1)* 每页显示记录数。

2.分页查询是数据库的方言,不同的数据库有不同的实现,mysql是limit。

3.如果查询的是第一页数据,起始索引可以省略,直接写为 limit 10。

编写顺序

select -> from -> where -> group by -> having -> order by -> limit

执行顺序

from -> where -> group by -> having -> select -> order by -> limit

(1)、基本查询(不带任何条件)

在基本查询的DQL语句中,不带任何的查询条件。

语法:

SELECT 字段信息 FROM 表名;

SELECT * FROM 表名;

注意 : * 号代表查询所有字段,在实际开发中尽量少用(不直观、影响效率)。

举例:

select name from person; // 从person表中查询 name 字段信息

select name,age from person; // 从person表中查询 name,age 字段信息

select * from person; // 从person表中查询 所有 字段信息

字段设置别名,语法:

select name as 别名, age as 别名 from users;

select name 别名, age 别名 from users;

去除重复记录(去重),语法:

distinct只能返回他的目标字段,而无法返回其他字段。

distinct不会过滤掉null值,返回结果包含null值;

distinct【查询字段】,必须放在要查询字段的开头,即放在第一个参数;

select distinct user_name '用户名称' from users; // 对单个字段去重

select distinct user_name,phone from users; // 对多个字段去重

select count(distinct user_name) from users; // 统计user_name不重复的总数

补充:

distinct方式就是两两对比,需要遍历整个表。

group by分组类似先建立索引再查索引,所以两者对比,小表destinct快,不用建索引。大表group by快。一般来说小表就算建索引,也不会慢到哪去,但是如果是TB级大表,遍历简直就是灾难。

所以很多Oracle项目都禁止使用distinct语句,全部要求替换成group by。

group 是按组查询的,是一种聚合查询,很多时候是为了做统计用。

distinct 是查询出来以后再把重复的去掉,性能上 group 比 distinct 要好很多。

case when

case when相当于if else语法,是一个表达式,表示对某些条件的判断并返回对应的结果。

语法:

case [匹配字段] when [条件] then [满足条件的处理] else [不满足条件的处理] end;

case [匹配字段] when [条件] then [满足条件的处理] [when then ...] else [不满足条件的处理] end;

case when [条件] then [满足条件的处理] else [不满足条件的处理] end as 别名;

注意事项:

1、在case函数中else部分如果不写,默认值是NULL

2、case后面字段可以省略

3、case函数只返回第一个符合条件的值,剩下的Case部分将会被自动忽略。

4、在Case函数中,可以使用BETWEEN,LIKE,IS NULL,IN,EXISTS等等。比如说使用IN,EXISTS,可以进行子查询,从而 实现更多的功能

举例:

case when score>=90 then 'A' when score>=80 then 'B' when score>=70 then 'C' else 'D' end;

select name,score,(case when score>=90 then 'A' when score>=80 then 'B' when score>=70 then 'C' else 'D' end) as grade from student;

总结:

select 与 case结合使用最大的好处有两点

一、在显示查询结果时可以灵活的组织格式

二、有效避免了多次对同一个表或几个表的访问。比如:统计男生数和女生数

select grade, count(case when sex = 1 then 1 else null end) 男生数, count(case when sex = 2 then 2 else null end) 女生数 from students group by grade;

(2)、条件查询(WHERE)

语法: SELECT 字段列表 FROM 表名 WHERE 条件列表;

**注意:无法使用比较运算符来比较 NULL 值,比如 =、< 或 <>。**我们必须使用 IS NULL 和 IS NOT NULL 操作符

比较运算符:

> :大于

>= :大于等于

< :小于

<= :小于等于

= :等于

<> 或 != :不等于(注意:在 SQL 的一些版本中,该操作符可被写成 !=)

between ... and ... :在某个范围之内(含最小,最大值)

in(...) :在in之后的列表中的值,多选一

like :占位符,模糊匹配( 【 _ 】 匹配单个字符,【%】匹配任意个字符)

is null :是null

is not null :不是null

逻辑运算符:

and 或 && :并且(多个条件同时满足)

or 或 || :或者(多个条件满足其中之一)

not 或 ! :非,不是

举例:

大于、大于等于、小于、小于等于、等于、不等于

select * from user where age > 50; // 从user表中查询 所有 字段信息 要满足age 大于 50的条件

select * from user where age >= 50; // 从user表中查询 所有 字段信息 要满足age 大于等于 50的条件

select * from user where age < 50; // 从user表中查询 所有 字段信息 要满足age 小于 50的条件

select * from user where age <= 50; // 从user表中查询 所有 字段信息 要满足age 小于等于 50的条件

select * from user where age=50; // 从user表中查询 所有 字段信息 要满足age = 50的条件

select age from user where name='悟空'; // 从user表中查询 age 字段信息 要满足name = 悟空的条件

select * from user where age != 50; // 从user表中查询 所有 字段信息 要满足age 不等于 50的条件(不等于方式一)

select * from user where age <> 50; // 从user表中查询 所有 字段信息 要满足age 不等于 50的条件(不等于方式二)

is null、is not null

select * from user where name is null; // 从user表中查询 所有 字段信息 要满足name 是 null的条件

select * from user where name is not null; // 从user表中查询 所有 字段信息 要满足name 不是 null的条件

between ... and ... :在某个范围之内(含最小,最大值)

select * from user where age between 18 and 30; // 从user表中查询 所有 字段信息 要满足age 是 18 到 30的条件(大小值不可颠倒)

select * from user where age >= 18 and age <= 30; // 从user表中查询 所有 字段信息 要满足age 大于等于 18 并且 小于等于 30的条件

select * from user where age not between 18 and 30; // 从user表中查询 所有 字段信息 要满足age 大于等于18 并且 小于等于30的条件(不是两者之间,方式一)

select * from user where not age >= 18 and age <= 30; // 从user表中查询 所有 字段信息 要满足age 大于等于18 并且 小于等于30的条件(不是两者之间,方式二)

in(...) :在in之后的列表中的值,多选一

select * from user where age in(18,30); // 从user表中查询 所有 字段信息 要满足age 是 18 或者 30 的条件(或者)

模糊查询like

  • %:代表0或多个未知字符
  • _:代表1个未知字符

以x开头 x%

以x结尾 %x

包含 %x%

第二个字符是x _x%

以x开头以y结尾 x%y

第二个是x,倒数第三个是y x%y _

select * from user where name like "孙%"; // 查询名字姓孙的用户信息

select * from user where name like "%三"; // 查询名字以三结尾的用户信息

select * from user where name like "_四"; // 查询名字第二个字为四的用户信息

select * from user where name like "%对%"; // 查询名字包含对的用户信息

and 或 && :并且(多个条件同时满足)

select * from user where name = '张三' and id = 1; // 从user表中查询 所有 字段信息 要满足name 等于 张三 并且 id 等于1的条件

select * from user where name = '张三' && id = 1; // 从user表中查询 所有 字段信息 要满足name 等于 张三 并且 id 等于1的条件

or 或 || :或者(多个条件满足其中之一)

select * from user where name = '张三' or id = 1; // 从user表中查询 所有 字段信息 要满足name 等于 张三 或者 id 等于1的条件(方式一)

select * from user where name = '张三' || id = 1; // 从user表中查询 所有 字段信息 要满足name 等于 张三 或者 id 等于1的条件(方式二)

(3)、聚合函数

注意:null值不参与所有聚合函数运算

**语法:**select 聚合函数(字段列表) from 表名;
count:统计数量;
max:最大值;
min:最小值;
avg:平均值;
sum:求和;

统计数量

select count(*) from user; // 统计用户总记录数

select count(name) from user; – 统计的是name字段不为null的记录数

select count(*) from test_table where name = '张三'; // 统计的是所有字段,查询条件为name等于‘张三’的记录数

平均值

select avg(age) from user; // 统计用户的平均年龄

最大、小值

select max(age) from user; // 统计用户的最大年龄

select min(age) from user; // 统计用户的最小年龄

求和

select sum(age) from user where workaddress = ‘西安’; // 统计西安地区用户的年龄之和

(4)、分组查询(group by)

group by 从字面上来理解,group 表示分组、by 后接字段名,表示根据某个字段进行分组。

group by 语句根据一个或多个字段对结果集进行分组(也就是把值相同的所有记录放到一个组中,显示组中一条记录)。

实现对每个组而不是对整个结果集统计。比如要统计每个部门人数。根据需要分组,比如要统计部门人数,就需要根据部门分组,看具体需求。

语法:select 字段列表 from 表名 [ where 条件 ] group by 分组字段名 [ having 分组 后过滤条件 ];

where与having区别

执行时机不同:where是分组之前进行过滤,不满足where条件,不参与分组;而having是分组之后对结果进行过滤。

判断条件不同:where不能对聚合函数进行判断,而having可以。

注意:

Mysql5.7+ group by新特性(sql_mode这个模式是默认开启 only_full_group_by)

在5.7版本以上mysql中使用group by语句进行分组时, 如果select的字段 , 不是完全对应的group by后面的字段 , 有其他字段 , 那么就会报这个错误

在mysql5.7以后执行:

select * from user group by name; 会报error:1055错误

select name,age from user group by name; 会报error:1055错误

解决方法:

1、语法调整

先明确group by分组的列,在明确select字段列表,比方说:select a,b from test group by a,b,c;

从语法格式来看,是先有分组,在确定检索的列,检索的列只能是参加分组了的列。

group by 后的a,b,c是先确定的,而select 后面的字段是可变的,但是必须是分组所用到的分组字段,否则报错1055;

2、通过mysql的any_value()函数

select a,any_value(b) b,any_value(c) as c from test group by a;

3、修改mysql配置,删除only_full_group_by属性

-- 查看当前配置项

select @@global.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

可以看到有一个ONLY_FULL_GROUP_BY , 这个就是严格控制group by 和select 字段的 , 在不改变sql语句的前提下 , 把这个去掉就可以了

-- 将 ONLY_FULL_GROUP_BY 去掉

set @@global.sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';

设置完后,如果不生效,可以退出重新登录

注意事项:

分组之后,查询的字段一般为聚合函数和分组字段,查询其他字段无任何意义。

执行顺序: where > 聚合函数 > having 。

支持多字段分组, 具体语法为 : group by columnA,columnB,...;

group by 必须放在 order by 和 limit之前,不然会报错。

使用group by的话,SELECT子句中的列名必须为分组列、聚合函数或常量。

group by 语句通常用于配合聚合函数(如 COUNT()、MAX() 等),根据一个或多个列对结果集进行分组。

select name,count(name) as cout from user group by name; // 查询 user 表 使用name分组字段进行分组,返回name字段信息以及出现的次数

select name,count(*) as count from user group by name having count >= 2; // 筛选出count大于等于2的

select name from user group by name having name like '张%'; // 查询 user 表 使用name分组字段进行分组,返回name字段以张开头的数据

(5)、排序查询(order by)

排序在日常开发中是非常常见的一个操作,有升序排序,也有降序排序。

语法:select 字段列表 from 表名 order by 字段1 排序方式1 , 字段2 排序方式2,...;

排序方式:

ASC : 升序(默认值),从小到大排列

DESC: 降序,从大到小排列

注意事项:

如果是升序, 可以不指定排序方式ASC ;

如果是多字段排序,当第一个字段值相同时,才会根据第二个字段进行排序;

如果存在 where 子句,那么 order by 必须放到 where 询句后面;

最后要注意order by的原则,写在最前面的字段,它的优先级最高;

举例:

select id,name from user order by id desc; // 根据id来进行降序排序

select * from user order by id asc , create_time desc; // 根据年龄进行升序排序 , 年龄相同 , 再按照入职时间进行降序排序

(6)、分页查询(limit)

分页操作在业务系统开发时,也是非常常见的一个功能,我们在网站中看到的各种各样的分页条,后台

都需要借助于数据库的分页操作。

语法:SELECT 字段列表 FROM 表名 LIMIT 起始索引, 查询记录数 ;

注意事项:

起始索引从0开始,起始索引 = (查询页码 - 1)* 每页显示记录数。

分页查询是数据库的方言,不同的数据库有不同的实现,MySQL中是LIMIT。

如果查询的是第一页数据,起始索引可以省略,直接简写为 limit 10。

举例:

select * from user limit 0,10; // 查询用户表,返回第一页,每页展示10条记录

select * from user limit 10; // 简写方式:查询用户表,返回第一页,每页展示10条记录

select * from user limit 10,10; // 查询用户表,返回第二页,每页展示10条记录