4、MYSQL-DQL-基本查询

DQL(数据查询)

数据库最重要功能,没有之一,并且应该根据需要对数据进行筛选以及确定以什么样的格式显示。

语法格式:

sql 复制代码
[]:表示可选项
<>:表示必选项

select
    [all/distinct]
    <目标列表达式1> [别名],
    <目标列表达式2> [别名],
    ...
from <表名/视图名> [别名],
     <表名/视图名> [别名],
     ...
[where <条件表达式>]
[group by <列名>]
[having <条件表达式>]
[order by <列名> [asc/desc]]
[limit <数字/列表>]

数据准备:

sql 复制代码
-- 创建数据库
create database if not exists mydb2;
use mydb2;
-- 创建商品表:
create table if not exists product(
    pid int primary key auto_increment, -- 商品编号
    pname varchar(20) not null, -- 商品名字
    price double, -- 商品价格
    category_id varchar(20) -- 商品所属分类
);

-- 向product表批量插入所有商品数据(包含家电、服饰、美妆、零食类)
insert into product(pid, pname, price, category_id)
values
  -- 家电类 (c001)
  (null, '海尔洗衣机', 5000, 'c001'),
  (null, '美的冰箱', 3000, 'c001'),
  (null, '格力空调', 5000, 'c001'),
  (null, '九阳电饭煲', 5000, 'c001'),
  
  -- 服饰类 (c002)
  (null, '啄木鸟衬衣', 300, 'c002'),
  (null, '恒源祥西裤', 800, 'c002'),
  (null, '花花公子夹克', 440, 'c002'),
  (null, '劲霸休闲裤', 266, 'c002'),
  (null, '海澜之家卫衣', 180, 'c002'),
  (null, '杰克琼斯运动裤', 430, 'c002'),
  
  -- 美妆类 (c003)
  (null, '兰蔻面霜', 300, 'c003'),
  (null, '雅诗兰黛精华水', 200, 'c003'),
  (null, '香奈儿香水', 350, 'c003'),
  (null, 'SK-II神仙水', 350, 'c003'),
  (null, '资生堂粉底液', 180, 'c003'),
  
  -- 零食类 (c004)
  (null, '老北京方便面', 56, 'c004'),
  (null, '良品铺子海带丝', 17, 'c004'),
  (null, '三只松鼠坚果', 88, null);

1. 运算符

通过运算符进行运算,可以获取到表结构以外的另一种数据,支持四种运算符,分别为:

1.1 算术运算符

算术运算符 说明
+ 加法运算
- 减法运算
* 乘法运算
/ 或 DIV 除法运算,返回商
% 或 MOD 求余运算,返回余数

1.2 比较运算符

比较运算符 说明
= 等于
< 和 <= 小于和小于等于
> 和 >= 大于和大于等于
<=> 安全的等于,两个操作数均为 NULL 时,其所得值为 1;而当一个操作数为 NULL 时,其所得值为 0
<> 或!= 不等于
IS NULL 或 ISNULL 判断一个值是否为 NULL
IS NOT NULL 判断一个值是否不为 NULL
LEAST 当有两个或多个参数时,返回最小值
GREATEST 当有两个或多个参数时,返回最大值
BETWEEN AND 判断一个值是否落在两个值之间
IN 判断一个值是 IN 列表中的任意一个值
NOT IN 判断一个值不是 IN 列表中的任意一个值
LIKE 通配符匹配
REGEXP 正则表达式匹配

1.3 逻辑运算符

逻辑运算符 说明
NOT 或者! 逻辑非
AND 或者 && 逻辑与
OR 或者 || 逻辑或
XOR 逻辑异或

1.4 位运算符(了解即可)

位运算符 说明
| 按位或
& 按位与
^ 按位异或
<< 按位左移
>> 按位右移
~ 按位取反,反转所有比特

2. 正则表达式

字符串匹配的规则。

模式 描述
^ 匹配输入字符串的开始位置。
$ 匹配输入字符串的结束位置。
. 匹配除 "\n" 之外的任何单个字符。
[...] 字符集合。匹配所包含的任意一个字符。例如,'[abc]' 可以匹配 "plain" 中的 'a'。
[^...] 负值字符集合。匹配未包含的任意字符。例如,'[^abc]' 可以匹配 "plain" 中的 'p'。
p1|p2|p3 匹配 p1 或 p2 或 p3。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f) ood' 则匹配 "zood" 或 "food"。
* 匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等价于 {0,}。
+ 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。
{n} n 是一个非负整数。匹配确定的 n 次。例如,'o {2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。
{n,m} m 和 n 均为非负整数,其中 n <= m。最少匹配 n 次且最多匹配 m 次。

举例:

sql 复制代码
-- 匹配成功返回1,否则返回0

-- ^ 在字符串开始处进行匹配
select 'abc' regexp '^a'; -- 字符串是否以a开头
select * from product where pname regexp '^海'; -- 商品是否以'海'开头

-- $ 在字符串末尾开始匹配
select 'abc' regexp 'a$'; -- 字符串是否以a结尾;
select * from product where pname regexp '水$'; -- 商品是否以'水'结尾

-- . 匹配任意字符,除换行符\n
select 'abc' regexp '.b';
select * from product where pname regexp '力.';

-- [...]匹配括号内的任意单个字符
select 'abc' regexp '[xyz]';
select 'abc' regexp '[xya]'; -- []中的任意字符串是否在前面字符串中出现

-- [^...]注意^符合只有在[]内才是取反的意思,在别的地方都是表示开始处匹配
select 'abc' regexp '[^xyz]';
select 'abc' regexp '[^xya]'; -- []中的任意字符串是否在前面字符串中出现

-- a* 匹配9个或多个a,包括空字符串。可以作为占位符使用.有没有指定字符都可以匹配到数据
select 'stab' regexp '.ta*b'; 
select 'stb' regexp '.ta*b';
select '' regexp 'a*'; -- 表示a可以出现0次或多次,换种方式讲:a可出现可不出现

-- a+ 匹配1个或者多个a,但是不包括空字符
select 'stab' regexp '.ta+b'; -- a要至少出现1次
select 'stb' regexp '.ta+b';

-- a? 匹配0个或者1个a
select 'stb' regexp '.ta?b';
select 'staab' regexp '.ta?b'; -- 表示a只能出现0次或者1次

-- a1|a2 匹配a1或者a2
select 'a' regexp 'a|b';
select 'a' regexp '^(a|b)';
select 'b' regexp '^(a|b)';
select 'c' regexp '^(a|b)';

-- a{m}匹配m个a
select 'staaab' regexp 'ta{3}';
select 'staaab' regexp 'a{4}';

-- a{m,}匹配m个或者更多个a
select 'staaab' regexp 'ta{3,}'; -- 表示至少出现3次,最多可以出现无限个a

-- a{m,n}匹配m到n个a,包含m和n
select 'staaab' regexp 'ta{1,4}'; -- 只需要出现1-4次直接都符合规则
select 'staaab' regexp 'ta{4,10}';

-- (abc) abc作为一个序列匹配,不用括号括起来都是用单个字符去匹配,如果要把多个字符作为一个整体去匹配就需要用到括号,所以括号适合上面的所有情况。
select 'xababy' regexp 'x(ab)*y'; -- ()表示一个整体
select 'xababy' regexp 'x(ab){3,4}y';

3. 条件查询

举例:

sql 复制代码
-- 算术运算符
select 6 + 2;
select 6 - 2;
select 6 * 2;
select 6 / 2;
select 6 % 2;

-- 将所有商品价格 +10 元
select pname, price + 10 as new_price from product;

-- 将所有商品价格上调 10%
select pname, price * 1.1 as new_price from product;

-- 查询商品名称为"海尔洗衣机"的商品所有信息:
select * from product where pname='海尔洗衣机';

-- 查询价格为800商品
select pname from product where price = 800;

-- 查询价格不是800的所有商品
select pname from product where price != 800;
select pname from product where price <> 800;
select pname from product where not(price = 800);

-- 查询商品价格大于60元的所有商品信息
select * from product where price >= 60;

-- 查询商品价格在200到1000之间所有商品
select pname from product where price between 200 and 1000;
select pname from product where price >= 200 && price <= 1000; 
select pname from product where price >= 200 and price <= 1000;

-- 查询商品价格是200或800的所有商品
select pname from product where price = 200 || price = 800; 
select pname from product where price = 200 or price = 800; 
select pname from product where price in(200,800);

-- 查询含有'鞋'字的所有商品
select pname from product where pname like '%鞋%'; -- %:用来匹配任意字符

-- 查询以'海'开头的所有商品
select * from product where pname like '海%';

-- 查询第二个字为'蔻'的所有商品
select * from product where pname like '_蔻%'; -- _:用来匹配单个字符

-- 查询category_id为null的商品
select pname from product where category_id is null;

-- 查询category_id不为null分类的商品
select pname from product where category_id is not null;

-- 使用 least 求最小值
select least(10,20);
select least(10,5,10) as small_number;
select least(10,5,null,40) as small_number; --如果有个值为null,则不会进行比较,直接输出null

-- 使用 greatest 求最大值
select greatest(10,20,40) as big_number;
select greatest(10,20,null,40) as big_number; --如果有个值为null,则不会进行比较,直接输出null

4. 排序查询

使用order by子句设定按照哪个字段哪种方式(asc/desc)进行排序。

语法格式:

sql 复制代码
select
    字段1,字段2,...
from 
    表名
order by 
    字段1 [asc/desc],字段2 [asc/desc],...;

特点:

  • asc代表升序,desc代表降序,不写默认升序。
  • order by 支持单个/多个字段、表达式、函数、别名。

举例:

sql 复制代码
-- 1.使用价格排序(降序)
select * from product order by price desc;

-- 2.在价格排序(降序)的基础上,以分类排序(降序)
select * from product order by price desc,category_id desc;

-- 3.显示商品的价格(去重复),并排序(降序)
select distinct price from product order by price desc;

5. 聚合查询

聚合查询是对一列的值进行计算,然后返回一个单一的值。

聚合函数 作用
count() 统计指定列不为 NULL 的记录行数;
sum() 计算指定列的数值和,如果指定列类型不是数值类型,那么计算结果为 0
max() 计算指定列的最大值,如果指定列是字符串类型,那么使用字符串排序运算;
min() 计算指定列的最小值,如果指定列是字符串类型,那么使用字符串排序运算;
avg() 计算指定列的平均值,如果指定列类型不是数值类型,那么计算结果为 0

⚠️:聚合函数对于NULL值的处理:

  • count(*) 会统计表中所有的记录行数,包括值为 NULL 的行;而 count(列名) 只统计该列不为 NULL 的记录数。

  • sum()avg() 等函数在遇到非数值类型或 NULL 值时,通常会忽略这些值,而不是直接返回 0。

举例:

sql 复制代码
-- 1 查询商品的总条数
select count(pname) from product;

-- 2 查询价格大于200商品的总条数
select count(pname) from product where price > 200;

-- 3 查询分类为'c001'的所有商品的价格总和
select sum(pname) from product where category_id = 'c001';

-- 4 查询商品的最大价格
select max(price) from product;

-- 5 查询商品的最小价格
select min(price) from product;
select max(price) as max_price,min(price) as min_price from product;

-- 6 查询分类为'c002'所有商品的平均价格
select avg(price) as avg_price from product order by category_id = 'c002';

6. 分组查询

使用group by对查询信息进行分组。

语法格式:

sql 复制代码
select
    字段1,字段2...
from
    表名
group by
    分组字段
having
    分组条件;

⚠️:

  • 使用group by,只能出现分组的字段和统计函数,其他的字段不能出现。
  • 不分组筛选用where,分组筛选用having。
  • group by子句用来分组where子句的输出。
  • having子句用来分组的结果进行筛选行。

举例:

sql 复制代码
-- 1 统计各个分类商品的个数
select category_id,count(pname) from product group by category_id;

-- 2.统计各个分类商品的个数,且只显示个数大于4的信息
select 
    category_id,count(pname) as cp_number 
from 
    product 
group by 
    category_id 
having 
    cp_number > 4
order by
    cp_numver;

7. 分页查询

由于数据量很大,因此需要对数据采取分页显示方式,使用limit,例如数据共30条,每页显示5条,则第一页为1-5条;第二页为6-10条。

语法格式:

sql 复制代码
m:整数,表示从第几条索引开始
n:整数,表示查询多少条数据

select
    字段1,字段2...
from
    表名
limit
    [n/m,n]

举例:

sql 复制代码
-- 查询product表的前5条记录
select * from product limit 5;

-- 从第4条开始显示,显示5条
select * from product limit 3,5;

8. 练习

数据准备1:

sql 复制代码
CREATE TABLE student(
    id INT,
    name VARCHAR(20),
    gender VARCHAR(20),
    chinese INT,
    english INT,
    math INT
);

INSERT INTO student(id, NAME, gender, chinese, english, math) VALUES(1, '张明', '男', 89, 78, 90);
INSERT INTO student(id, NAME, gender, chinese, english, math) VALUES(2, '李进', '男', 67, 53, 95);
INSERT INTO student(id, NAME, gender, chinese, english, math) VALUES(3, '王五', '女', 87, 78, 77);
INSERT INTO student(id, NAME, gender, chinese, english, math) VALUES(4, '李一', '女', 88, 98, 92);
INSERT INTO student(id, NAME, gender, chinese, english, math) VALUES(5, '李财', '男', 82, 84, 67);
INSERT INTO student(id, NAME, gender, chinese, english, math) VALUES(6, '张宝', '男', 55, 85, 45);
INSERT INTO student(id, NAME, gender, chinese, english, math) VALUES(7, '黄蓉', '女', 75, 65, 30);
INSERT INTO student(id, NAME, gender, chinese, english, math) VALUES(7, '黄蓉', '女', 75, 65, 30);

举例:

sql 复制代码
-- 查询表中所有学生的信息。
select * from student;

-- 查询表中所有学生的姓名和对应的英语成绩。
select name,english from student;

-- 过滤表中重复数据。
select distinct * from student;

-- 统计每个学生的总分。
select name, sum(chinese + english + math) as total_score from student;

-- 在所有学生总分数上加10分特长分。
select name, sum(chinese + english + math) + 10 as new_sum_score from student;

-- 使用别名表示学生分数。
select name, (chinese + english + math) as score from student;

-- 查询英语成绩大于90分的同学
select * from student where english > 90;

-- 查询总分大于200分的所有同学
select name, sum(chinese + english + math) as sum_score from student where sum_score > 200;

-- 查询英语分数在 89-90之间的同学。
select * from student where english between 89 and 90;

-- 查询英语分数不在 80---90之间的同学。
select * from student where english not between 80 and 90;
 
-- 查询数学分数为89,90,91的同学。
select * from student where math=89 || math=90 || math=91;

-- 查询所有姓李的学生英语成绩。
select name,english from student where name like '李%';

-- 查询数学分80并且语文分80的同学。
select * from student where math=80 and chinese = 80;

-- 查询英语80或者总分200的同学
select * from student where english=80 || (chinese + english + math) =200;

-- 对数学成绩降序排序后输出。
select * from student order by math desc;

-- 对总分排序后输出,然后再按从高到低的顺序输出
select * from student order by (chinese + english + math) desc;

-- 对姓李的学生成绩排序输出
select * from student where name like '李%' order by chinese,english,math;

-- 查询男生和女生分别有多少人,并将人数降序排序输出
select gender,count(gender) as count_gender from student group by gender order by count_gender desc;

数据准备2:

sql 复制代码
use mydb2;

CREATE TABLE emp(
    empno INT, -- 员工编号
    ename VARCHAR(50), -- 员工名字
    job VARCHAR(50), -- 工作名字
    mgr INT, -- 上级领导编号
    hiredate DATE, -- 入职日期
    sal INT, -- 薪资
    comm INT, -- 奖金
    deptno INT -- 部门编号
);

INSERT INTO emp VALUES(7369,'SMITH','CLERK',7902,'1980-12-17',800,NULL,20);
INSERT INTO emp VALUES(7499,'ALLEN','SALESMAN',7698,'1981-02-20',1600,300,30);
INSERT INTO emp VALUES(7521,'WARD','SALESMAN',7698,'1981-02-22',1250,500,30);
INSERT INTO emp VALUES(7566,'JONES','MANAGER',7839,'1981-04-02',2975,NULL,20);
INSERT INTO emp VALUES(7654,'MARTIN','SALESMAN',7698,'1981-09-28',1250,1400,30);
INSERT INTO emp VALUES(7698,'BLAKE','MANAGER',7839,'1981-05-01',2850,NULL,30);
INSERT INTO emp VALUES(7782,'CLARK','MANAGER',7839,'1981-06-09',2450,NULL,10);
INSERT INTO emp VALUES(7788,'SCOTT','ANALYST',7566,'1987-04-19',3000,NULL,20);
INSERT INTO emp VALUES(7839,'KING','PRESIDENT',NULL,'1981-11-17',5000,NULL,10);
INSERT INTO emp VALUES(7844,'TURNER','SALESMAN',7698,'1981-09-08',1500,0,30);
INSERT INTO emp VALUES(7876,'ADAMS','CLERK',7788,'1987-05-23',1100,NULL,20);
INSERT INTO emp VALUES(7900,'JAMES','CLERK',7698,'1981-12-03',950,NULL,30);
INSERT INTO emp VALUES(7902,'FORD','ANALYST',7566,'1981-12-03',3000,NULL,20);
INSERT INTO emp VALUES(7934,'MILLER','CLERK',7782,'1982-01-23',1300,NULL,10);

举例:

sql 复制代码
-- 1、按员工编号升序排列不在19号部门工作的员工信息
select * from emp
where not in(deptno = 19)
order by empno;

-- 2、查询姓名第二个字母不是"A"且薪水大于1000元的员工信息,按年薪降序排列
select * from emp
where ename not like '_A%' && sal > 1000
order by (12 * sal + comm) desc;

-- 3、求每个部门的平均薪水
select deptno,avg(sal) as avg_sal from emp
group by deptno;

-- 4、求各个部门的最高薪水
select 
    deptno,max(sal) as max_sal
from 
    emp
group by 
    deptno;

-- 5、求每个部门每个岗位的最高薪水
select 
    deptno,job,max(sal) as max_sal
from 
    emp
group by 
    deptno,job
order by 
    deptno;

-- 6、求平均薪水大于2000的部门编号
select 
    deptno,avg(sal) as avg_sal
from 
    emp
group by
    deptno
having
    avg_sal >2000;

-- 7、将部门平均薪水大于1500的部门编号列出来,按部门平均薪水降序排列
select
    deptno,avg(sal) as avg_sal
from
    emp
group by
    deptno
having
    avg_sal > 1500
order by avg_sal desc;

-- 8、选择公司中有奖金的员工姓名,工资
select
    ename,sal
from
    emp
where 
    comm != NULL;

-- 9、查询员工最高工资和最低工资的差距
select max(sal) - min(sal) from emp;
相关推荐
ID_180079054732 小时前
Python采集京东商品详情:基于官方API的规格与价格获取
开发语言·数据库·python
w_t_y_y2 小时前
数据库连接池(一)HikariCP
数据库
sheji70093 小时前
Springboot家教平台中心系统53754--(程序+源码+数据库+调试部署+开发环境)
java·数据库·spring boot·后端·spring·旅游
小宋10213 小时前
Java 数据库访问 vs Python 数据库访问:JDBC vs ORM
java·数据库·python
少云清3 小时前
【安全测试】6_数据库安全性测试 _数据备份、加密、审计、认证
数据库·安全性测试
kyle~3 小时前
Redis(Remote Dictionary Server)
数据库·redis·缓存
砚边数影4 小时前
架构实战:如何利用融合数据库破解用户画像系统的存储瓶颈?
数据库·mongodb·架构·kingbase·数据库平替用金仓·金仓数据库
不剪发的Tony老师4 小时前
FlySpeed:一款通用的SQL查询工具
数据库·sql
攻城狮7号4 小时前
物联网时代2026年时序数据库选型指南
数据库·物联网·时序数据库·apache iotdb