数据库基础:DQL 数据查询语言

数据库基础:DQL 数据查询语言

前言 :本文是"数据库基础"系列的第六篇。上一篇我们完成了 MySQL 的安装和基础操作,学会了创建数据库、创建表和简单的增删改查。本篇我们将正式进入 SQL 语言中最核心的部分------DQL 数据查询语言(Data Query Language)。在数据库操作中,查询是最频繁、最复杂的操作,掌握 SELECT 语句的各种用法,是数据库开发的必备技能。

目录

  • 一、数据准备
  • 二、基础查询
  • 三、条件查询
  • 四、排序查询
  • 五、常见函数
  • 六、分组函数
  • 七、分组查询
  • 八、连接查询
  • 九、子查询
  • 十、分页查询
  • 十一、union 联合查询
  • 十二、总结

一、数据准备

1.1 导入数据

本篇章使用 myemployees.sql 示例数据库,包含员工、部门、位置、工种四张表。

Navicat 导入步骤

步骤 操作
1 打开 Navicat,连接到 MySQL(master)
2 右键点击连接 → 选择"新建数据库",命名为 myemployees,字符集选择 utf8mb4
3 双击打开 myemployees 数据库(高亮显示)
4 右键点击 myemployees → 选择"运行 SQL 文件"
5 选择 myemployees.sql 文件,点击"开始"
6 等待执行完成,刷新表列表

命令行导入方式(备选):

bash 复制代码
mysql -uroot -p myemployees < /root/myemployees.sql

1.2 表结构说明

员工表(employees)
字段 类型 长度 备注
employee_id int - 员工编号
first_name varchar 20
last_name varchar 25
email varchar 25 邮箱
phone_number varchar 20 电话号码
job_id varchar 10 工作编号
salary double 10,2 月薪
commission_pct double 4,2 奖金率
manager_id int - 上级领导的员工编号
department_id int - 部门编号
hiredate datetime - 入职日期
部门表(departments)
字段 类型 长度 备注
department_id int - 部门编号
department_name varchar 3 部门名称
manager_id int - 部门领导的员工编号
location_id int - 位置编号
工种表(jobs)
字段 类型 长度 备注
job_id varchar 10 工种编号
job_title varchar 35 工种名称
min_salary int - 最低工资
max_salary int - 最高工资
位置表(locations)
字段 类型 长度 备注
location_id int - 位置编号
street_address varchar 40 街道
postal_code varchar 12 邮编
city varchar 30 城市
state_province varchar 25 州/省
country_id varchar 2 国家编号

二、基础查询

2.1 基本语法

sql 复制代码
SELECT 查询列表 FROM 表名;

语法说明

部分 说明
SELECT 标识选择哪些列(字段、常量、表达式、函数)
FROM 标识从哪个表中查询
查询列表 可以是表中的字段、常量值、表达式、函数

特点

  • 查询列表可以是:表中的字段、常量值、表达式、函数
  • 查询的结果是一个虚拟的表格,不会改变原表数据

2.2 查询单个字段

sql 复制代码
-- 查询员工表中的姓名字段
SELECT last_name FROM employees;

2.3 查询多个字段

sql 复制代码
-- 查询员工表中的员工编号、名、姓
SELECT employee_id, first_name, last_name FROM employees;

2.4 查询所有字段

方式一:列出所有字段

sql 复制代码
SELECT employee_id, first_name, last_name, email, phone_number, 
       job_id, salary, commission_pct, manager_id, department_id, hiredate 
FROM employees;

方式二 :使用 * 通配符

sql 复制代码
SELECT * FROM employees;

建议:在开发中建议写明具体字段名,避免查询不需要的数据,影响性能。

2.5 查询常量值

sql 复制代码
-- 查询数值常量
SELECT 66;

-- 查询字符串常量
SELECT "bigdata";

2.6 查询表达式

sql 复制代码
-- 查询表达式计算结果
SELECT 100 * 2;

2.7 查询函数

sql 复制代码
-- 查询当前 MySQL 版本
SELECT VERSION();

2.8 起别名(AS)

作用

  • 便于理解
  • 如果查询的字段有重名的情况,使用别名可以区分开来

方式一 :使用 AS 关键字

sql 复制代码
-- 给表达式起别名
SELECT 100 * 2 AS 结果;

-- 给字段起别名
SELECT first_name AS 名, last_name AS 姓 FROM employees;

方式二:使用空格

sql 复制代码
SELECT first_name 名, last_name 姓 FROM employees;

特殊场景:别名中包含特殊字符(如空格),需要加引号

sql 复制代码
-- 查询 salary,显示结果为 "out put"(包含空格)
SELECT salary AS "out put" FROM employees;

2.9 去重(DISTINCT)

sql 复制代码
-- 查询员工表中涉及到的所有部门编号(去重)
SELECT DISTINCT department_id FROM employees;

2.10 + 号的作用

MySQL 中的 +只有一个功能:运算符

规则

情况 结果
两个操作数都为数值型 做加法运算,如 SELECT 66 + 99;
一方为字符型,可转换为数值 转换后做加法运算,如 SELECT '88' + 66;
一方为字符型,不可转换 将字符型转换为 0 再做运算,如 SELECT 'abc' + 66;
一方为 NULL 结果必定为 NULL,如 SELECT NULL + 10;
sql 复制代码
-- 查询员工名和姓连成一个字段,显示为姓名
-- 错误写法(+ 不能拼接字符串)
SELECT last_name + first_name AS 姓名 FROM employees;  

-- 正确写法(使用 CONCAT 函数)
SELECT CONCAT(last_name, first_name) AS 姓名 FROM employees; 

-- 拼接示例
SELECT CONCAT('h', 'e', 'l', 'l', 'o') AS 结果;

三、条件查询(WHERE)

3.1 基本语法

sql 复制代码
SELECT 查询列表
FROM 表名
WHERE 筛选条件;

执行顺序FROMWHERESELECT

3.2 筛选条件分类

分类 说明 运算符
按条件表达式筛选 使用比较运算符进行筛选 ><=!=<>)、>=<=
按逻辑表达式筛选 使用逻辑运算符连接多个条件 AND&&)、OR(`
模糊查询 使用关键字进行模糊匹配 LIKEBETWEEN ANDINIS NULL

3.3 按条件表达式筛选

sql 复制代码
-- 查询工资大于 12000 的员工信息
SELECT *
FROM employees
WHERE salary > 12000;

-- 查询部门编号不等于 90 的员工
SELECT last_name, department_id
FROM employees
WHERE department_id <> 90;

3.4 按逻辑表达式筛选

逻辑运算符 说明
AND&& 两个条件都为 TRUE,结果为 TRUE
OR(`
NOT! 如果条件本身为 FALSE,结果为 TRUE
sql 复制代码
-- 查询工资在 10000 到 20000 之间的员工
SELECT last_name, salary
FROM employees
WHERE salary >= 10000 AND salary <= 20000;

-- 查询部门编号为 90 或 100 的员工
SELECT last_name, department_id
FROM employees
WHERE department_id = 90 OR department_id = 100;

3.5 模糊查询

LIKE

特点:一般和通配符搭配使用。

通配符 说明
% 匹配任意多个字符(包含 0 个字符)
_ 匹配任意单个字符
sql 复制代码
-- 查询员工名中包含字符 a 的员工信息
SELECT *
FROM employees
WHERE first_name LIKE '%a%';

-- 查询员工名中第三个字符为 e,第五个字符为 a 的员工名和工资
SELECT first_name, salary
FROM employees
WHERE first_name LIKE '__e_a%';

-- 查询员工姓中第二个字符为 _ 的员工名(使用 \ 转义)
SELECT last_name
FROM employees
WHERE last_name LIKE '_\_%';

-- 使用 ESCAPE 指定转义字符
SELECT last_name
FROM employees
WHERE last_name LIKE '_$_%' ESCAPE '$';

说明ESCAPE 关键字用于指定一个字符替代 \ 的转义作用。

BETWEEN AND

特点

  • 使用 BETWEEN AND 可以提高语句的简洁度
  • 包含临界值
  • 两个临界值不要调换顺序(必须小值在前,大值在后)
sql 复制代码
-- 查询员工编号在 100 到 120 之间的员工信息
SELECT *
FROM employees
WHERE employee_id BETWEEN 100 AND 120;
IN

特点

  • 判断某个字段的值是否属于 IN 列表中的某一项
  • 使用 IN 提高语句简洁度
  • IN 列表的值类型必须一致或兼容
sql 复制代码
-- 查询员工的工种编号是 IT_PROG、AD_VP、AD_PRES 中的一个
SELECT first_name, job_id
FROM employees
WHERE job_id IN ('IT_PROG', 'AD_VP', 'AD_PRES');
IS NULL

特点

  • =<> 不能用于判断 NULL
  • IS NULLIS NOT NULL 可以判断 NULL
sql 复制代码
-- 查询没有奖金的员工名和奖金率
SELECT first_name, commission_pct
FROM employees
WHERE commission_pct IS NULL;

-- 查询有奖金的员工名和奖金率
SELECT first_name, commission_pct
FROM employees
WHERE commission_pct IS NOT NULL;

3.6 安全等于(<=>)

<=> 是 MySQL 特有的安全等于运算符,既可以判断 NULL 值,也可以判断普通数值

sql 复制代码
-- 查询没有奖金的员工(使用 <=>)
SELECT first_name, commission_pct
FROM employees
WHERE commission_pct <=> NULL;

-- 查询工资为 12000 的员工
SELECT *
FROM employees
WHERE salary <=> 12000;

IS NULL<=> 对比

对比项 IS NULL <=>
可读性
判断 NULL 可以 可以
判断普通值 不可以 可以

建议 :可读性较高,建议使用 IS NULL 判断 NULL 值。

四、排序查询(ORDER BY)

4.1 基本语法

sql 复制代码
SELECT 字段列表 FROM 表名 ORDER BY 排序字段 [ASC|DESC];
关键字 说明
ASC 升序(默认)
DESC 降序

4.2 单字段排序

sql 复制代码
-- 按工资降序排列
SELECT last_name, salary 
FROM employees 
ORDER BY salary DESC;

-- 按工资升序排列(默认)
SELECT last_name, salary 
FROM employees 
ORDER BY salary ASC;

4.3 多字段排序

sql 复制代码
-- 先按部门编号升序,再按工资降序
SELECT last_name, department_id, salary 
FROM employees 
ORDER BY department_id ASC, salary DESC;

五、常见函数

5.1 字符函数

LENGTH
sql 复制代码
-- 获取字符串长度
SELECT LENGTH('hello') AS 长度;

-- 获取姓名的长度
SELECT last_name, LENGTH(last_name) FROM employees;
CONCAT
sql 复制代码
-- 拼接字符串
SELECT CONCAT(last_name, '的邮箱是', email) FROM employees;
UPPER / LOWER
sql 复制代码
-- 大小写转换
SELECT UPPER('hello') AS 大写, LOWER('HELLO') AS 小写;

-- 将姓转为大写,名转为小写
SELECT UPPER(last_name), LOWER(first_name) FROM employees;
SUBSTR
sql 复制代码
-- 截取子串(从第1位开始取3个字符)
SELECT SUBSTR('hello world', 1, 3) AS 截取结果;

-- 取姓名的前3个字符
SELECT SUBSTR(last_name, 1, 3) FROM employees;
REPLACE
sql 复制代码
-- 替换字符串
SELECT REPLACE('hello world', 'world', 'mysql') AS 替换结果;

-- 将邮箱中的'g'替换为'G'
SELECT REPLACE(email, 'g', 'G') FROM employees;

5.2 数学函数

sql 复制代码
-- 取绝对值
SELECT ABS(-10) AS 绝对值;

-- 向上取整
SELECT CEIL(3.14) AS 向上取整;

-- 向下取整
SELECT FLOOR(3.99) AS 向下取整;

-- 四舍五入
SELECT ROUND(3.14159, 2) AS 四舍五入;

-- 取随机数(0-1之间)
SELECT RAND() AS 随机数;

5.3 日期函数

sql 复制代码
-- 获取当前日期和时间
SELECT NOW() AS 当前日期时间;

-- 获取当前日期
SELECT CURDATE() AS 当前日期;

-- 获取当前时间
SELECT CURTIME() AS 当前时间;

-- 获取年月日
SELECT YEAR(NOW()) AS 年, MONTH(NOW()) AS 月, DAY(NOW()) AS 日;

-- 查询入职于1992年的员工
SELECT last_name, hiredate 
FROM employees 
WHERE YEAR(hiredate) = 1992;

-- 日期计算:入职满10年
SELECT last_name, hiredate, 
       DATE_ADD(hiredate, INTERVAL 10 YEAR) AS 满10年日期
FROM employees;

5.4 流程控制函数

IF
sql 复制代码
-- IF(条件, 真值, 假值)
SELECT last_name, salary, 
       IF(salary > 10000, '高薪', '普通') AS 薪资等级
FROM employees;
CASE
sql 复制代码
-- CASE WHEN 条件 THEN 结果 ELSE 结果 END
SELECT last_name, salary,
       CASE 
           WHEN salary > 15000 THEN 'A'
           WHEN salary > 10000 THEN 'B'
           WHEN salary > 5000 THEN 'C'
           ELSE 'D'
       END AS 薪资等级
FROM employees;

六、分组函数

6.1 分组函数列表

函数 说明
COUNT() 统计行数
SUM() 求和
AVG() 求平均值
MAX() 求最大值
MIN() 求最小值

6.2 案例实操

sql 复制代码
-- 统计员工总数
SELECT COUNT(*) FROM employees;

-- 统计有部门编号的员工数(不包含 NULL)
SELECT COUNT(department_id) FROM employees;

-- 计算员工的平均工资
SELECT AVG(salary) FROM employees;

-- 计算员工的最高工资
SELECT MAX(salary) FROM employees;

-- 计算员工的最低工资
SELECT MIN(salary) FROM employees;

-- 计算员工的工资总和
SELECT SUM(salary) FROM employees;

-- 同时查询多个统计值
SELECT 
    COUNT(*) AS 人数,
    AVG(salary) AS 平均工资,
    MAX(salary) AS 最高工资,
    MIN(salary) AS 最低工资,
    SUM(salary) AS 工资总和
FROM employees;

七、分组查询(GROUP BY)

7.1 基本语法

sql 复制代码
SELECT 分组字段, 聚合函数 FROM 表名 GROUP BY 分组字段;

7.2 案例实操

sql 复制代码
-- 按部门分组,统计每个部门的员工数
SELECT department_id, COUNT(*) AS 人数
FROM employees
GROUP BY department_id;

-- 按部门分组,计算每个部门的平均工资
SELECT department_id, AVG(salary) AS 平均工资
FROM employees
GROUP BY department_id;

-- 按职位分组,统计每个职位的最高工资
SELECT job_id, MAX(salary) AS 最高工资
FROM employees
GROUP BY job_id;

7.3 HAVING(分组后的条件筛选)

语法

sql 复制代码
SELECT 分组字段, 聚合函数 
FROM 表名 
GROUP BY 分组字段 
HAVING 条件;

WHERE 在分组前筛选,HAVING 在分组后筛选。

案例实操

sql 复制代码
-- 查询平均工资大于 10000 的部门
SELECT department_id, AVG(salary) AS 平均工资
FROM employees
GROUP BY department_id
HAVING AVG(salary) > 10000;

-- 查询员工数大于 5 的部门
SELECT department_id, COUNT(*) AS 人数
FROM employees
GROUP BY department_id
HAVING COUNT(*) > 5;

八、连接查询(JOIN)

8.1 等值连接(旧语法)

sql 复制代码
-- 查询员工的姓名和所在部门的名称
SELECT e.last_name, d.department_name
FROM employees e, departments d
WHERE e.department_id = d.department_id;

8.2 INNER JOIN(内连接)

语法

sql 复制代码
SELECT 字段列表
FROM 表1
INNER JOIN 表2 ON 连接条件;

案例实操

sql 复制代码
-- 查询员工的姓名、部门名称和职位名称
SELECT e.last_name, d.department_name, j.job_title
FROM employees e
INNER JOIN departments d ON e.department_id = d.department_id
INNER JOIN jobs j ON e.job_id = j.job_id;

8.3 LEFT JOIN(左外连接)

语法

sql 复制代码
SELECT 字段列表
FROM 表1
LEFT JOIN 表2 ON 连接条件;

说明:返回左表所有记录,右表无匹配则显示 NULL。

案例实操

sql 复制代码
-- 查询所有部门及其员工人数(包括空部门)
SELECT d.department_name, COUNT(e.employee_id) AS 人数
FROM departments d
LEFT JOIN employees e ON d.department_id = e.department_id
GROUP BY d.department_id;

-- 查询没有员工的部门
SELECT d.department_name
FROM departments d
LEFT JOIN employees e ON d.department_id = e.department_id
WHERE e.employee_id IS NULL;

8.4 RIGHT JOIN(右外连接)

语法

sql 复制代码
SELECT 字段列表
FROM 表1
RIGHT JOIN 表2 ON 连接条件;

说明:返回右表所有记录,左表无匹配则显示 NULL。

九、子查询

9.1 WHERE 子句中的子查询

sql 复制代码
-- 查询工资高于平均工资的员工
SELECT last_name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);

9.2 使用 IN 的子查询

sql 复制代码
-- 查询部门名称中包含 'IT' 的部门的员工
SELECT last_name, department_id
FROM employees
WHERE department_id IN (
    SELECT department_id 
    FROM departments 
    WHERE department_name LIKE '%IT%'
);

9.3 FROM 子句中的子查询(派生表)

sql 复制代码
-- 查询每个部门的平均工资,再按平均工资排序
SELECT department_id, avg_salary
FROM (
    SELECT department_id, AVG(salary) AS avg_salary
    FROM employees
    GROUP BY department_id
) AS dept_avg
ORDER BY avg_salary DESC;

9.4 SELECT 子句中的子查询(标量子查询)

sql 复制代码
-- 查询每个员工的姓名及其部门的平均工资
SELECT 
    last_name, 
    salary,
    (SELECT AVG(salary) FROM employees e2 WHERE e2.department_id = e1.department_id) AS 部门平均工资
FROM employees e1;

十、分页查询(LIMIT)

10.1 基本语法

sql 复制代码
SELECT 字段列表 FROM 表名 LIMIT 起始索引, 条数;
参数 说明
起始索引 从第几条开始(从 0 开始)
条数 每页显示多少条

10.2 案例实操

sql 复制代码
-- 查询前 5 条数据
SELECT * FROM employees LIMIT 5;

-- 查询第 6 到第 10 条数据
SELECT * FROM employees LIMIT 5, 5;

-- 分页公式:LIMIT (页数-1)*每页条数, 每页条数
-- 第1页(每页5条)
SELECT * FROM employees LIMIT 0, 5;

-- 第2页
SELECT * FROM employees LIMIT 5, 5;

-- 第3页
SELECT * FROM employees LIMIT 10, 5;

十一、UNION 联合查询

11.1 基本语法

sql 复制代码
SELECT 字段列表 FROM 表1
UNION
SELECT 字段列表 FROM 表2;

11.2 案例实操

sql 复制代码
-- 查询部门编号为 80 的员工姓名和部门编号为 90 的员工姓名
SELECT last_name, department_id FROM employees WHERE department_id = 80
UNION
SELECT last_name, department_id FROM employees WHERE department_id = 90;

-- 查询工资大于 10000 的员工和奖金率为空的员工
SELECT last_name, salary, commission_pct FROM employees WHERE salary > 10000
UNION
SELECT last_name, salary, commission_pct FROM employees WHERE commission_pct IS NULL;

十二、总结

核心知识点速查

知识点 关键语法
基础查询 SELECT 字段 FROM 表名
条件查询 WHERE 条件
模糊查询 LIKE '%模式%'
排序 ORDER BY 字段 DESC
分组统计 GROUP BY 字段
分组筛选 HAVING 条件
内连接 INNER JOIN ... ON
左连接 LEFT JOIN ... ON
子查询 SELECT ... FROM (...) AS 别名
分页查询 LIMIT 起始索引, 条数
联合查询 UNION

注意事项

要点 说明
WHERE vs HAVING WHERE 分组前筛选,HAVING 分组后筛选
COUNT(*) vs COUNT(字段) COUNT(*) 包含 NULL,COUNT(字段) 不包含 NULL
别名 AS 可省略,但建议保留
模糊查询性能 % 开头的模糊查询不会使用索引
分页查询 LIMIT 是 MySQL 特有语法,其他数据库不通用
UNION 默认去重,UNION ALL 不去重效率更高

系列直达

相关推荐
昌原的儿子LEO3 小时前
Linux IO多路复用与SQLite数据库核心知识点总结
linux·数据库·oracle
山岚的运维笔记3 小时前
mysql 专业笔记 -- 第 8 章:使用变量
运维·数据库·笔记·后端·学习·mysql·dba
聚美智数3 小时前
网安查询-备案查询-网络安全查询API接口介绍
网络·数据库·web安全
坐吃山猪4 小时前
【多线程】Semaphore使用
java·数据库·oracle·多线程
数智启示录4 小时前
PostgreSQL 内存调优实战(第 12 篇):work_mem 只调大 64 倍,峰值为什么远不止 64 倍
运维·数据库·经验分享·postgresql·面试
姜太小白5 小时前
【Oracle】记排查sh脚本调用SQL执行卡顿的排查总结
数据库·sql·oracle
bgy66665 小时前
MariaDB 数据库 基础详解
数据库·mariadb
自动化监测Learner5 小时前
QGIS 把geojson数据导入 PostgreSQL/PostGIS 的完整流程
数据库·postgresql
虎虎(_ _)。゜zzZ5 小时前
Qdrant向量数据库工程实战
数据库·人工智能·大模型·向量数据库·rag·qdrant