当前位置:首页 > 随笔 > 正文内容

MySQL 高级查询技巧与多表关联实战

访客 随笔 2026年7月1日 1

构建基础数据模型

在执行高级查询之前,需要先构建具备关联关系的数据表。以下是重构后的业务表结构及初始化数据脚本:

1. 组织架构表(sys_dept)

CREATE TABLE sys_dept (
    dept_id INT AUTO_INCREMENT PRIMARY KEY,
    dept_name VARCHAR(100) NOT NULL,
    parent_dept_id INT DEFAULT NULL,
    CONSTRAINT fk_parent_dept FOREIGN KEY (parent_dept_id) REFERENCES sys_dept(dept_id)
);

INSERT INTO sys_dept (dept_id, dept_name, parent_dept_id) VALUES
(10, '研发中心', NULL),
(20, '人力资源部', NULL),
(30, '前端组', 10),
(40, '后端组', 10);

2. 员工信息表(sys_employee)

CREATE TABLE sys_employee (
    emp_no INT PRIMARY KEY,
    full_name VARCHAR(100) NOT NULL,
    base_salary DECIMAL(12, 2) NOT NULL,
    belong_dept INT,
    CONSTRAINT fk_emp_dept FOREIGN KEY (belong_dept) REFERENCES sys_dept(dept_id)
);

INSERT INTO sys_employee (emp_no, full_name, base_salary, belong_dept) VALUES
(101, '张三', 15000.00, 30),
(102, '李四', 18000.00, 30),
(103, '王五', 22000.00, 40),
(104, '赵六', 12000.00, 20);

3. 客户档案表(biz_client)与交易订单表(biz_order)

CREATE TABLE biz_client (
    client_id INT PRIMARY KEY,
    client_name VARCHAR(100) NOT NULL,
    last_order_date DATE
);

CREATE TABLE biz_order (
    order_no INT PRIMARY KEY,
    client_id INT,
    created_at DATE,
    current_state VARCHAR(50),
    CONSTRAINT fk_order_client FOREIGN KEY (client_id) REFERENCES biz_client(client_id)
);

INSERT INTO biz_client (client_id, client_name) VALUES 
(1, '甲企业'), 
(2, '乙企业');

INSERT INTO biz_order (order_no, client_id, created_at, current_state) VALUES
(1001, 1, '2023-05-10', '待支付'),
(1002, 1, '2023-06-15', '已完成'),
(1003, 2, '2023-05-20', '待支付');

MySQL 高级查询实战场景

1. 相关子查询(Correlated Subquery)

通过嵌套查询获取每个部门中薪资最高的员工明细。外部查询与内部查询通过部门ID产生联动。

SELECT d.dept_name, e.full_name, e.base_salary
FROM sys_dept d
INNER JOIN sys_employee e ON d.dept_id = e.belong_dept
WHERE e.base_salary = (
    SELECT MAX(sub_e.base_salary)
    FROM sys_employee sub_e
    WHERE sub_e.belong_dept = e.belong_dept
);

2. 集合操作(UNION 与 UNION ALL)

合并不同数据源的结果集。UNION 会自动去除重复记录,而 UNION ALL 则保留所有行,执行效率更高。

-- 合并本月活跃用户与历史VIP用户名单(自动去重)
SELECT user_id FROM active_users_monthly
UNION
SELECT user_id FROM vip_users_history;

-- 保留重复记录的合并操作
SELECT user_id FROM active_users_monthly
UNION ALL
SELECT user_id FROM vip_users_history;

3. 多表内连接(INNER JOIN)

提取所有已成交订单及其归属客户的名称,仅返回两个表中匹配成功的记录。

SELECT o.order_no, c.client_name, o.created_at
FROM biz_order o
INNER JOIN biz_client c ON o.client_id = c.client_id
WHERE o.current_state = '已完成';

4. 自关联查询(Self Join)

将同一张表视为两张不同的表进行关联,常用于处理树状层级结构,如展示子部门及其对应的上级部门。

SELECT 
    parent.dept_name AS superior_dept, 
    child.dept_name AS sub_dept
FROM sys_dept parent
LEFT JOIN sys_dept child ON child.parent_dept_id = parent.dept_id;

5. 分组聚合与条件过滤(GROUP BY & HAVING)

使用聚合函数统计数据,并通过 HAVING 子句对分组后的结果进行二次筛选。

-- 计算各部门的薪资总支出
SELECT belong_dept, SUM(base_salary) AS total_payroll
FROM sys_employee
GROUP BY belong_dept;

-- 筛选出员工人数达到或超过2人的部门
SELECT belong_dept, COUNT(emp_no) AS headcount
FROM sys_employee
GROUP BY belong_dept
HAVING headcount >= 2;

6. 窗口函数(Window Functions)

利用 OVER() 子句在不减少原表行数的情况下进行聚合或排名计算。DENSE_RANK() 可保证排名连续。

-- 在部门内部按薪资降序生成密集排名
SELECT 
    emp_no, 
    base_salary, 
    belong_dept,
    DENSE_RANK() OVER (PARTITION BY belong_dept ORDER BY base_salary DESC) AS salary_rank
FROM sys_employee;

7. 复杂多表更新(Multi-table UPDATE)

在更新数据时关联多张表。以下示例根据订单表中的最新交易时间,批量修正客户档案表中的最后下单日期。

UPDATE biz_client c
INNER JOIN (
    SELECT client_id, MAX(created_at) AS latest_order
    FROM biz_order
    GROUP BY client_id
) recent_orders ON c.client_id = recent_orders.client_id
SET c.last_order_date = recent_orders.latest_order;

相关文章

可以按小时收费的VPS

很多 VPS 提供商都支持 按小时计费(hourly billing),想短期试用 / 临时搭建节点、测试网络、短期项目等场景非常合适。下面是当前最主流且靠谱的按小时 VPS 选项,分别按不同需求场景整理: 1. Vultr(全球节点,包括日本) 按小时计费 可选机房:东京 / 大阪 / 洛杉矶 / 法兰克福 / 伦敦 … 支持 PayPal(部分情况),但更常用信用卡/PayPal+卡价格参考$...

在 iPhone 上下载国外App

地区/国家限制App Store 会根据 Apple ID 的国家或地区限制应用下载。如果你的 Apple ID 绑定的是中国大陆,就可能无法下载 OpenAI 官方的 ChatGPT 应用,因为它在大陆 App Store 不上架。解决办法:换成美国、加拿大、香港等地区的 Apple ID。或者在现有 Apple ID 上更改地区。注册一个国外 Apple ID(推荐)比如注册 美国区 Appl...

Node.js 中的异步编程:回调与 Promise

Node.js 是一个基于 JavaScript 构建的单线程、非阻塞运行环境,它通过异步编程机制来高效处理多个操作。在执行如文件读取、API 请求或数据库查询等任务时,Node.js 不会等待这些操作完成,而是使用回调函数和 Promise 来避免阻塞主线程。 回调方式实现异步 那么当异步操作完成后,Node.js 如何知道接下来要做什么呢?这就要用到 回调函数(callback)。 回调本质上...

Selenium自动化测试入门指南

Selenium自动化测试入门指南

什么是自动化测试? 自动化测试是指利用软件工具自动执行测试用例,模拟用户操作,如打开网页、点击链接、输入文本等,并验证结果是否符合预期。 其主要优点包括: 大幅减少人工成本 测试速度快 可以在非工作时间运行 支持持续集成和交付 然而,它也存在一些局限性,例如开发成本较高、不适合快速变化的项目、依赖稳定的UI界面等。 自动化测试的应用条件 适合引入自动化测试的情况包括: 手动测试耗时且需要大量...

MariaDB Galera集群故障快速恢复指南

OpenStack控制节点采用三节点MariaDB Galera集群架构。当数据库集群因故障重启时,有时会出现Galera集群无法正常启动的问题。虽然有多种方法可以恢复数据库服务,但如何实现快速启动同时确保数据完整性呢? 通过分析日志发现,MariaDB Galera集群节点宕机时会在日志中输出以下信息: [Note] WSREP: 新集群视图:全局状态: 874d8e7e-5980-11e8-8...

Android 中 EventBus 的通信机制与实现原理深度解析

EventBus 核心设计思想 EventBus 是一个基于观察者模式的事件总线框架,广泛应用于 Android 平台以实现组件解耦。它通过中心化的消息分发机制,使不同层级、不同线程的对象能够以"发布-订阅"方式通信,避免了传统接口回调或广播带来的强依赖问题。 核心角色说明 事件(Event):任意 Java 对象,作为数据载体,如网络状态变更通知、用户登录信息等。 发布者(Publi...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。