四、表关系与复杂查询

一、表关系设计与约束

1. 表关系类型与实现

关系类型实现方式示例场景
一对一共享主键 或 外键唯一约束用户 ↔ 用户详细信息
一对多外键约束部门 ↔ 员工
多对多中间表 + 联合主键学生 ↔ 课程

2. 核心约束类型

-- 完整表创建示例(含约束)
CREATE TABLE employees (
    emp_id INT PRIMARY KEY AUTO_INCREMENT,      -- 主键约束
    emp_name VARCHAR(50) NOT NULL,              -- 非空约束
    email VARCHAR(100) UNIQUE,                  -- 唯一约束
    dept_id INT,
    salary DECIMAL(10,2) CHECK (salary > 0),    -- 检查约束(MySQL 8.0+)
    FOREIGN KEY (dept_id) REFERENCES departments(dept_id) -- 外键约束
);
约束类型详解
约束类型作用注意事项
PRIMARY KEY唯一标识记录,自动创建聚集索引每表只能有一个主键
FOREIGN KEY强制引用完整性可能影响性能,高并发慎用
UNIQUE保证字段值唯一可空字段允许存在多个NULL值
CHECK自定义验证规则MySQL 8.0前需通过触发器实现
NOT NULL禁止空值与DEFAULT配合使用更安全

二、索引与查询优化

1. 索引的作用与类型

索引类型特点适用场景
B-Tree索引默认索引,支持范围查询大多数场景(如WHERE、ORDER BY)
唯一索引强制字段值唯一身份证号、邮箱等字段
联合索引多列组合索引常一起查询的字段组合

2. 索引创建与使用

-- 创建索引
CREATE INDEX idx_emp_name ON employees(emp_name);  -- 单列索引
CREATE UNIQUE INDEX idx_email ON employees(email);-- 唯一索引
CREATE INDEX idx_dept_salary ON employees(dept_id, salary); -- 联合索引

-- 查看索引
SHOW INDEX FROM employees;

-- 删除索引
DROP INDEX idx_emp_name ON employees;

3. 索引优化原则

  1. 最左前缀原则:联合索引 (A,B,C) 可生效于:

    • WHERE A=1
    • WHERE A=1 AND B=2
    • WHERE A=1 AND B=2 AND C=3
  2. 避免过度索引:索引会降低写操作速度

  3. 覆盖索引:查询字段全部在索引中时,无需回表

    -- 使用覆盖索引
    SELECT emp_name FROM employees WHERE emp_name LIKE '张%';
    

三、高级关联查询

1. JOIN 执行原理

-- 示例:三表关联
-- 查询部门名称、员工姓名及其领导的项目名称
SELECT 
    d.dept_name,        -- 选择部门名称
    e.emp_name,         -- 选择员工姓名
    p.project_name      -- 选择项目名称
FROM departments d      -- 从部门表开始查询
JOIN employees e        -- 连接员工表
    ON d.dept_id = e.dept_id  -- 连接条件:部门ID匹配
LEFT JOIN projects p    -- 左连接项目表
    ON e.emp_id = p.leader_id;  -- 连接条件:员工ID与项目领导ID匹配
JOIN 执行顺序
  1. 执行 FROM departments d
  2. 执行 JOIN employees e → 生成中间结果集
  3. 执行 LEFT JOIN projects p → 扩展结果集
  4. 应用 WHERE 过滤(如果有)
  5. 执行 SELECT 字段投影

2. 自连接(Self Join)

-- 查询在同一部门中的不同员工对
SELECT 
    e1.emp_name AS employee1,  -- 选择第一个员工的姓名
    e2.emp_name AS employee2   -- 选择第二个员工的姓名
FROM employees e1              -- 从员工表(别名 e1)开始查询
JOIN employees e2              -- 自连接员工表(别名 e2)
  ON e1.dept_id = e2.dept_id   -- 连接条件:部门ID相同
  AND e1.emp_id < e2.emp_id;   -- 确保员工ID不同且避免重复配对

3. 递归查询(WITH RECURSIVE)

-- 使用递归CTE生成从1到10的数字序列
WITH RECURSIVE numbers(n) AS (  -- 定义递归CTE,命名为numbers,包含列n
    SELECT 1                    -- 初始查询:从1开始
    UNION ALL                   -- 递归部分:将结果与后续查询合并
    SELECT n+1 FROM numbers     -- 递归查询:每次将n的值加1
    WHERE n < 10                -- 递归终止条件:n小于10时继续递归
)
SELECT * FROM numbers;          -- 最终查询:返回递归CTE的结果

四、综合案例:电商系统优化

1. 带约束的表设计

--产品表(products)
CREATE TABLE products (
    product_id INT PRIMARY KEY AUTO_INCREMENT,  -- 产品ID,主键,自增
    product_name VARCHAR(255) NOT NULL,    -- 产品名称,必填
    price DECIMAL(10,2) CHECK (price >= 0),    -- 产品价格,必须大于等于0
    stock INT DEFAULT 0 CHECK (stock >= 0)    -- 库存数量,默认值为0,必须大于等于0
);

CREATE TABLE orders (
    order_id INT PRIMARY KEY AUTO_INCREMENT,    -- 订单ID,主键,自增
    user_id INT NOT NULL,    -- 用户ID,必填,外键关联用户表
    order_date DATETIME DEFAULT CURRENT_TIMESTAMP,    -- 订单日期,默认值为当前时间
    status ENUM('pending', 'shipped', 'completed') DEFAULT 'pending',    -- 订单状态,枚举类型,默认值为'pending'
    FOREIGN KEY (user_id) REFERENCES users(user_id)    -- 外键约束,关联用户表的user_id字段
);

-- 中间表(含联合主键)
CREATE TABLE order_items (
    order_id INT,    -- 订单ID,联合主键之一,外键关联订单表
    product_id INT,    -- 产品ID,联合主键之一,外键关联产品表
    quantity INT CHECK (quantity > 0),    -- 购买数量,必须大于0
    PRIMARY KEY (order_id, product_id),    -- 联合主键,由order_id和product_id组成
    FOREIGN KEY (order_id) REFERENCES orders(order_id),    -- 外键约束,关联订单表的order_id字段
    FOREIGN KEY (product_id) REFERENCES products(product_id)    -- 外键约束,关联产品表的product_id字段
);

2. 索引优化实战

-- 高频查询:按用户和状态查订单
CREATE INDEX idx_user_status ON orders(user_id, status);

-- 高频搜索:商品名称模糊查询
CREATE FULLTEXT INDEX idx_product_name ON products(product_name);

-- 使用全文索引查询
SELECT * FROM products 
WHERE MATCH(product_name) AGAINST('手机 -配件' IN BOOLEAN MODE);

3. 复杂业务查询

-- 统计每个用户的2023年度消费总金额(包含未消费用户)
SELECT 
    u.user_name,                             -- 用户姓名
    --当SUM的结果为NULL时,COALESCE会返回0
    COALESCE(SUM(oi.quantity * p.price), 0) AS total_spent  -- 计算消费总金额(未消费显示0)
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id          -- 关联用户和订单表(保留未下单用户)
LEFT JOIN order_items oi ON o.order_id = oi.order_id  -- 关联订单和订单明细表
LEFT JOIN products p ON oi.product_id = p.product_id  -- 关联订单明细和商品表
WHERE o.order_date BETWEEN '2023-01-01' AND '2023-12-31'  -- 筛选2023年订单
GROUP BY u.user_id;                          -- 按用户ID分组汇总消费金额

-- 查找库存紧张的热销商品(销量TOP 10且库存<100)
SELECT 
    p.product_name,                         -- 商品名称
    SUM(oi.quantity) AS total_sold,         -- 统计商品总销量
    p.stock                                 -- 显示当前库存量
FROM products p
JOIN order_items oi ON p.product_id = oi.product_id  -- 关联商品和订单明细表
GROUP BY p.product_id                       -- 按商品ID分组统计销量
HAVING total_sold > 100 AND stock < 100     -- 筛选销量>100且库存<100的商品
ORDER BY total_sold DESC                    -- 按销量降序排列
LIMIT 10;                                   -- 仅显示销量最高的前10条记录

五、常见错误与调试技巧

1. 外键约束冲突

错误示例

-- 尝试删除有子记录的部门
DELETE FROM departments WHERE dept_id = 1;
-- 报错:Cannot delete or update a parent row: a foreign key constraint fails

解决方案

-- 方法1:先删除子记录
DELETE FROM employees WHERE dept_id = 1;
DELETE FROM departments WHERE dept_id = 1;

-- 方法2:使用级联删除(设计表时定义)
CREATE TABLE employees (
    ...
    FOREIGN KEY (dept_id) 
      REFERENCES departments(dept_id)
      ON DELETE CASCADE
);

2. 索引失效场景

场景示例优化方案
对索引列使用函数WHERE YEAR(create_time)=2023改为范围查询:WHERE create_time BETWEEN '2023-01-01' AND '2023-12-31'
使用前导通配符模糊查询WHERE name LIKE '%张三%'使用全文索引或倒序存储
隐式类型转换WHERE id = '100'(id为INT)保持类型一致:WHERE id = 100

六、实战练习建议

1. 设计医院管理系统

  • 核心表:患者表、医生表、科室表、预约记录表、病历表
  • 要求
    1. 实现多对多关系(医生-科室)
    2. 添加合理的约束(如预约时间不能早于当前时间)
    3. 创建必要的索引
    4. 编写以下查询:
      • 查找某科室最繁忙的医生
      • 统计各科室的预约成功率
      • 检索患者的完整就诊历史

2. 性能优化挑战

  1. 对已有慢查询进行 EXPLAIN 分析
  2. 通过索引优化将查询时间从 2s 降至 200ms 以内
  3. 使用 FORCE INDEX 强制使用特定索引对比效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/978633.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

18439二维前缀和

18439二维前缀和 ⭐️难度&#xff1a;中等 &#x1f4d6; &#x1f4da; import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner new Scanner(System.in);int n scanner.nextInt();int m scanner.nextInt();int q s…

PwnLab详细解答

一、主机发现 arp-scan -l靶机ip&#xff1a;192.168.55.153 二、端口识别、目录枚举、指纹识别 2.1端口识别 nmap -p- 192.168.55.1532.2目录枚举 dirb http://192.168.55.153枚举出来的敏感目录找到了文件上传网站和上传的地址 2.3指纹识别 nmap 192.168.55.153 -sV -…

傅里叶分析

傅里叶分析之掐死教程&#xff08;完整版&#xff09;更新于2014.06.06 要让读者在不看任何数学公式的情况下理解傅里叶分析。 傅里叶分析不仅仅是一个数学工具&#xff0c;更是一种可以彻底颠覆一个人以前世界观的思维模式。但不幸的是&#xff0c;傅里叶分析的公式看起来太复…

unity学习56:旧版legacy和新版TMP文本输入框 InputField学习

目录 1 旧版文本输入框 legacy InputField 1.1 新建一个文本输入框 1.2 InputField 的子物体构成 1.3 input field的的component 1.4 input Field的属性 2 过渡 transition 3 控件导航 navigation 4 占位文本 placeholder 5 文本 text 5.1 文本内容&#xff0c;用户…

详解Tomcat下载安装以及IDEA配置Tomcat(2023最新)

目录 步骤一&#xff1a;首先确认自己是否已经安装JDK步骤二&#xff1a;下载安装Tomcat步骤三&#xff1a;Tomcat配置环境变量步骤四&#xff1a;验证Tomcat配置是否成功步骤五&#xff1a;为IDEA配置Tomcat 步骤一&#xff1a;首先确认自己是否已经安装JDK jdk各版本通用安…

《Qt动画编程实战:轻松实现头像旋转效果》

《Qt动画编程实战&#xff1a;轻松实现头像旋转效果》 Qt 提供了丰富的动画框架&#xff0c;可以轻松实现各种平滑的动画效果。其中&#xff0c;旋转动画是一种常见的 UI 交互方式&#xff0c;广泛应用于加载指示器、按钮动画、场景变换等。本篇文章将详细介绍如何使用 Qt 实现…

从零构建知识库:AI如何实现“问题即答案”?

在当今这个信息爆炸的时代&#xff0c;如何高效地获取和利用知识成为了各行各业面临的共同挑战。构建知识库&#xff0c;作为整合、存储和检索信息的重要手段&#xff0c;正在逐步成为企业提升竞争力的关键。而AI技术的加入&#xff0c;更是让这一过程实现了质的飞跃&#xff0…

PhotoDoodle: Learning Artistic Image Editing from Few-Shot Examples 论文解读

目录 一、概述 二、PhotoDoodle 1、OmniEditor的预训练 2、DiT重点 3、无噪声条件范式与CFM 4、EditLoRA 4.1关于LoRA 4.2关于EditLoRA 三、相关工作 一、概述 风格化图像编辑的论文&#xff01; 介绍了PhotoDoodle&#xff0c;一个基于扩散模型的图像编辑框架&#x…

RabbitMQ操作实战

1.RabbitMQ安装 RabbitMQ Windows 安装、配置、使用 - 小白教程-腾讯云开发者社区-腾讯云下载erlang&#xff1a;http://www.erlang.org/downloads/https://cloud.tencent.com/developer/article/2192340 Windows 10安装RabbitMQ及延时消息插件rabbitmq_delayed_message_exch…

【Java项目】基于Spring Boot的校园博客系统

【Java项目】基于Spring Boot的校园博客系统 技术简介&#xff1a;采用Java技术、Spring Boot框架、MySQL数据库等实现。 系统简介&#xff1a;校园博客系统是一个典型的管理系统&#xff0c;主要功能包括管理员&#xff1a;首页、个人中心、博主管理、文章分类管理、文章信息…

【时时三省】(C语言基础)整型数据

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 整型数据 &#xff08;1&#xff09;基本整型&#xff08;int型&#xff09; 编译系统分配给int型数据2个字节或4个字节&#xff08;由具体的C编译系统自行决定&#xff09;。在存储单元中…

Ollama下载安装+本地部署DeepSeek+UI可视化+搭建个人知识库——详解!(Windows版本)

目录 1️⃣下载和安装Ollama 1. &#x1f947;官网下载安装包 2. &#x1f948;安装Ollama 3.&#x1f949;配置Ollama环境变量 4、&#x1f389;验证Ollama 2️⃣本地部署DeepSeek 1. 选择模型并下载 2. 验证和使用DeepSeek 3️⃣使用可视化工具 1. Chrome插件-Page …

数据库的sql语句

本篇文章主要用来收集项目开发中&#xff0c;遇到的各种sql语句的编写。 1、根据user表的role_id字段&#xff0c;查询role表。 sql语句&#xff1a;使用JOIN连接两个表 SELECT u.*,r.rolename FROM user u JOIN role r ON u.role_id r.id WHERE u.id 1; 查询结果&#xff1a…

Grok 3 vs. DeepSeek vs. ChatGPT:2025终极AI对决

2025 年,AI 领域的竞争愈发激烈,三个重量级选手争夺霸主地位:Grok 3(由 xAI 开发)、DeepSeek(国内 AI 初创公司)和 ChatGPT(OpenAI 产品)。每个模型都有自己独特的优势,无论是在深度思考、速度、编程辅助、创意输出,还是在成本控制方面,都展现出强大的实力。但究竟…

手机大厂如何处理安卓分屏退出后最近任务显示一半问题?

背景&#xff1a; 近来在有学员朋友在群里讨论到了一个分屏退出后&#xff0c;在桌面最近任务中的卡片显示异常问题&#xff0c;虽然他的问题和目前市场上的最近任务显示一半情况不一样。但是这里也刚好启发了群里vip学员们对这个最近任务对分屏task只显示一半画面问题进行相关…

Spring Cloud——路由网关Zuul

??? 哈喽&#xff01;大家好&#xff0c;我是【一心同学】&#xff0c;一位上进心十足的【Java领域博主】&#xff01;??? 【一心同学】的写作风格&#xff1a;喜欢用【通俗易懂】的文笔去讲解每一个知识点&#xff0c;而不喜欢用【高大上】的官方陈述。 【一心同学】博客…

WorldQuant Brain的专属语言——Fast Expression

使用brain需要的编程语言 在使用BRAIN平台时往往不需要事先有编码背景&#xff0c;因此小白也能很快对其上手&#xff0c;但有经验的程序员来讲&#xff0c;该平台暂时没有禁止API通信低强度进行时的程序化访问&#xff08;但是非常不好意思&#x1f623;怎么访问我没找到&…

人大金仓KCA | 对象访问权限入门

人大金仓KCA | 对象访问权限入门 一、知识预备1. 对象的分类2. 对象访问权限概述3. 级联授权4. 权限描述符5. 使用EasyKStudio查看用户权限 二、案例实施1. 用户授权综合案例2. 对象的创建者默认就是对象的所属主3. 该表对象的所属主4. 对象属主的权限设置5. 授权普通用户访问对…

StrokesPlus【电脑鼠标键盘手势软件】v0.5.8.0 中文绿色便携版

前言 StrokesPlus.net是一个超方便的手势识别软件&#xff0c;它能帮你用手势来代替鼠标和键盘操作。用起来既简单又灵活&#xff0c;功能还特别强大。 操作起来非常简单&#xff0c;它有好多实用的功能&#xff0c;比如智能识别你写的字、设定手势操作的区域、模拟鼠标的各种…

springBoot统一响应类型3.1版本

前言&#xff1a; 通过实践而发现真理&#xff0c;又通过实践而证实真理和发展真理。从感性认识而能动地发展到理性认识&#xff0c;又从理性认识而能动地指导革命实践&#xff0c;改造主观世界和客观世界。实践、认识、再实践、再认识&#xff0c;这种形式&#xff0c;循环往…