MySQL多表查询中的笛卡尔积问题


精选专栏链接 🔗


  • MySQL技术笔记专栏
  • Redis技术笔记专栏
  • 大模型搭建专栏
  • Python学习笔记专栏
  • 深度学习算法专栏

欢迎订阅,点赞+关注,每日精进1%,与百万开发者共攀技术珠峰

更多内容持续更新中!希望能给大家带来帮助~ 😀😀😀


MySQL多表查询中的笛卡尔积问题

  • 1,为什么需要多表查询
  • 2,什么是笛卡尔积
  • 3,多表查询的笛卡尔积错误
    • 3.1,笛卡尔积错误案例
    • 3.2,笛卡尔积错误的分析和解决
    • 3.3,公共字段的处理
  • 练习


1,为什么需要多表查询

多表查询,也称为关联查询,指两个或更多个表一起完成查询操作。

可进行多表查询的前提条件: 这些一起查询的表之间是有关系的(一对一、一对多),它们之间一定是有关联字段,比如:员工表和部门表,这两个表依靠“部门编号”进行关联。

案例说明为什么需要多表查询:

如下图所示的是一个项目的三张表:EMPLOYEES表(员工表)、DEPARTMENTS表、LOCATIONS表。

在这里插入图片描述
显然,我们可以得到如下信息:

  • EMPLOYEES 表和DEPARTMENTS表通过 department_id 字段相关联;
  • DEPARTMENT表和 LOCATIONS 表通过 location_id 字段相关联;

如果我们现在有一个新需求:要求查询员工名为 “Abel” 的人在哪个城市工作?

显然 EMPLOYEES 表中没有城市这个字段,城市字段位于 LOCATIONS 表内。
我们可以通过如下步骤完成此需求。

第一步:在EMPLOYEES表内查询Abel的员工信息

SQL语句如下:

SELECT * 
FROM employees
WHERE last_name = 'Abel';

运行结果如下:

在这里插入图片描述
可以看到Abel 所在的 department_id 为80。

第二步:在DEPARTMENT表内查询department_id 为80的部门信息

SQL语句如下:

SELECT *
FROM departments
WHERE department_id = 80;

运行结果如下:

在这里插入图片描述
可以看到department_id 为80的部门对应的location_id是2500。

第二步:在LOCATIONS表内查询location_id是2500的地址信息

SQL语句如下:

SELECT *
FROM locations 
WHERE location_id = 2500;

运行结果如下:

在这里插入图片描述
由此可见,员工Abel的工作城市是Oxford


写了三条SQL语句才实现此需求,找到了Abel的工作城市,这样是很不方便的,而且在高并发的系统中,执行多个SQL语句对效率和性能的影响是比较大的(相当于多次交互)。因此要引入多表查询,通过多表查询可以实现 一条SQL语句完成此需求。


2,什么是笛卡尔积

笛卡尔乘积是一个数学运算。假设我有两个集合 X 和 Y,那么 X 和 Y 的笛卡尔积就是 X 和 Y 的所有可能组合,也就是第一个对象来自于 X,第二个对象来自于 Y 的所有可能。组合的个数即为两个集合中元素个数的乘积数。如下图所示:

在这里插入图片描述


3,多表查询的笛卡尔积错误

多表查询的一个常见错误就是笛卡尔积错误。


3.1,笛卡尔积错误案例

当我们有如下需求时:

需求:查询每一位员工的employee_id和department_name。

注意: 如下图所示,员工的employee_id位于EMPLOYEES表,而department_name字段位于DEPARTMENTS表。

在这里插入图片描述

如果执行如下SQL语句,得到的是错误结果:

SELECT employee_id,department_name
FROM employees,departments;  

运行结果如下:

在这里插入图片描述

一共查询出2889条记录,而EMPLOYEES表有107条记录;DEPARTMENTS表有27条记录。27✖107=2889,它把每个员工都与每个部门匹配了一遍,显然这是一种错误的实现方式,具体来说是出现了笛卡尔积的错误。

错误的原因是:缺少了多表的连接条件。


3.2,笛卡尔积错误的分析和解决

笛卡尔积错误会在下面条件下产生:

  • 省略多个表的连接条件(或关联条件);
  • 连接条件(或关联条件)失效;
  • 所有表中的所有行互相连接;

正确的多表查询需要有连接条件。为了避免笛卡尔积错误,可以通过WHERE子句加入有效的连接条件。

加入连接条件后的查询语法如下:

SELECT table1.column, table2.column
FROM  table1, table2
WHERE table1.column1 = table2.column2;  #连接条件

因此,正确的SQL语句应该是:

SELECT employee_id,department_name
FROM employees,departments
# 两个表的连接条件
WHERE employees.department_id = departments.department_id;

运行结果如下:

在这里插入图片描述

此时查询得到的结果才是正常的。

注意:如上SQL查询得到106条记录,而EMPLOYEES表内有107条记录,原因是EMPLOYEES表中存在一条记录的 department_id 字段为Null。

在这里插入图片描述


3.3,公共字段的处理

一个细节问题是:如果查询语句中出现了多个表中都存在的字段,则必须指明此字段所在的表。接下来结合案例解释:

需求:查询每一位员工的employee_id、department_name、department_id。

如果执行如下SQL:

SELECT employee_id,department_name,department_id
FROM employees,departments
WHERE employees.`department_id` = departments.department_id;

执行报错:

在这里插入图片描述

原因是:EMPLOYEES表和DEPARTMENTS表都存在字段 departmen_id,SQL语句中没有明确指出查询哪个表中的 departmen_id 字段。

因此正确的SQL语句是:

# 如果查询语句中出现了多个表中都存在的字段,则必须指明此字段所在的表。
SELECT employee_id,department_name,employees.department_id
FROM employees,departments
WHERE employees.`department_id` = departments.department_id;

运行结果如下:

在这里插入图片描述
我们了解到,如果查询语句中出现了多个表中都存在的字段,则必须指明此字段所在的表。对此规则进行拓展:从sql优化的角度,建议多表查询时,每个字段前都指明其所在的表。

因为如果不指明字段所在的表,MySQL会自己去两张表中找此字段,找到后还需要检查另外一张表中是否存在此字段。这会在一定程度上影响查询的性能。因此建议多表查询时,每个字段前都指明其所在的表。

即,更好的SQL语句如下:

SELECT employees.employee_id,departments.department_name,employees.department_id
FROM employees,departments
WHERE employees.`department_id` = departments.department_id;

练习

我们再提出一个新的需求用做练习。

需求:查询每一位员工的employee_id、last_name、department_name、city。

在这里插入图片描述

SQL语句如下:

SELECT e.employee_id,e.last_name,d.department_name,l.city,e.department_id,l.location_id
FROM employees e,departments d,locations l
WHERE e.`department_id` = d.`department_id`
AND d.`location_id` = l.`location_id`;

因此可以总结出规律:如果有n个表实现多表的查询,则需要至少n-1个连接条件。


在这里插入图片描述

欢迎订阅,点赞+关注,每日精进1%,与百万开发者共攀技术珠峰

更多内容持续更新中!希望能给大家带来帮助~ 😀😀😀

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度解析 HTML `loading` 属性:优化网页性能的秘密武器

在开发网页时,我常常被页面加载速度慢的问题困扰,尤其是在图片和嵌入内容较多的页面上。用户还没看到内容就可能因为等待时间过长而离开,这对用户体验和 SEO 都是致命打击。后来,我发现了 HTML 的 loading 属性——一个简单却强大…

[C/C++内存安全]_[中级]_[安全处理字符串]

场景 在现代C开发指南出来后,并不建议使用C的某些内存不安全的字符串处理函数。那么有哪些函数不安全? 说明 内存安全方面,肯定是要向Rust看齐的。使用标准std::string字符串类,很大情况能避免缓冲区溢出问题。 如果旧项目里有…

【CNN】卷积神经网络- part1

1.卷积1.局部连接定义:只是于输入数据的一部分区域相连,每个神经元只关注一小部分作用:模仿人类的视野机制,极大的减少了模型参数的数量,降低了计算成本2.权重共享定义:所有神经元使用相同的权重向量来检测…

漏洞生命周期管理:从发现到防护的全流程方案

漏洞并非孤立存在,而是遵循 “发现→评估→修复→验证→闭环” 的生命周期。多数企业安全事件的根源并非缺乏漏洞发现能力,而是对漏洞生命周期的管理缺失 —— 大量漏洞被发现后长期未修复,或修复后未验证效果。构建全流程漏洞生命周期管理体…

opencv图像基本操作解析与实操

图片操作cv2.namedWindow() 创建命名窗口cv2.imshow()显示窗口cv2.destroyAllwindws()摧毁窗口cv2.resizeWindow()改变窗口大小cv2.waitKey()等待用户输入cv2.imread()读取图像img.shape 图片h、w、c(高、宽、通道数import cv2 # opencv读取的格式是BGR import m…

kafka--基础知识点--6.1--LEO、HW、LW

在 Apache Kafka 中,LEO(Log End Offset)、HW(High Watermark)、和 LW(Low Watermark) 是副本机制和日志管理中的核心概念,共同确保数据一致性、可见性和存储效率。以下是它们的详细…

在线深凹槽深检测方法都有哪些 —— 激光频率梳 3D 轮廓检测

引言在制造业中,深凹槽深度的精确检测是保证零部件质量的关键环节。随着智能制造的推进,在线检测需求日益迫切,传统检测方法在效率和精度上的不足逐渐显现。本文将梳理在线深凹槽深的传统检测方法,并重点探讨激光频率梳 3D 轮廓检…

NumPy 数组拼接的高级技巧与实践

在数据处理和机器学习领域,NumPy 是 Python 中最核心的科学计算库之一。NumPy 数组(ndarray)的拼接操作是数据预处理中极为常见的需求。本文将深入探讨如何将不同形状的 NumPy 数组进行拼接,特别是如何将多个一维数组与二维数组进…

原创-基于 PHP 和 MySQL 的证书管理系统 第三版

第一版属于开源版本,所以后台功能没有开发许多出来,今天分享证书查询第三版; 通过几天的紧急写代码及测试;第三版基本可以上线上,不过后面有一些BUG只能一边修复。 演示地址:物星科云证书管理系统 第三版…

爬虫虚拟环境

conda create --name myrepenv python3.12创建一个名为 myrepenv、Python 版本为 3.12 的全新 Conda 虚拟环境,适合需要隔离依赖或测试不同 Python 版本的项目。我的方式创建(需要指定盘符)conda create --prefixD:\Anaconda3\envs\myrepenv python3.12展示所下的co…

Netty集群方案详解与实战(Zookeeper + Redis + RabbitMQ)

一、背景 二、Netty 单体架构的优缺点 优点 缺点 三、Netty 集群架构的优缺点 优点 缺点 四、适用场景对比 五、Netty单体架构代码实现 六、Netty集群架构方案实现 方案一、Nginx负载均衡实现集群(较为简单) Nginx配置 前端连接方式 方案二、NacosGateway(结合…

Oracle迁移到高斯,查询字段默认小写,解决办法

一、问题说明 Oracle中,查询结果字段默认大写。高斯中,查询结果字段默认小写。在Mybatis的xml中,如果查询语句使用Map接收查询结果,使用resultType"java.util.HashMap"或resultType"Map"等写法,返…

Android Jetpack Compose + MVVM 开发流程深度分析

核心组件关系图 [View] -- 观察 --> [ViewModel] -- 操作 --> [Repository]| | Compose UI StateFlow/LiveData| | 用户交互事件 Room/Retrofit| …

Tailwind CSS快速上手 Tailwind CSS的安装、配置、使用

📚前言 在Web前端开发的历史长河中,CSS的编写方式经历了多次演进,从早期的原生CSS 到 CSS预处理(Less/Sass/Stylus) 到 CSS-in-JS(Styled-Components/Emotion) 再到 Utility-First 原子化CSS。每一种演进方案其本质都是围绕“开发效率”、“…

单例模式的智慧:从UVM看控制的艺术

有时候,生活中的很多东西其实只需要一个就够了,就像一个公司只需要一个CEO,一个王朝只需要一个皇帝。在UVM验证环境中,也有很多这样的需求——有些对象,我们希望它在整个仿真过程中只存在一个实例。这就是我们今天要聊…

Hexo - 免费搭建个人博客01 - 安装软件工具

导言我的博客:https://q164129345.github.io/ Hexo 作为一个 Node.js 框架,它依赖于 Node.js 运行时环境来执行。 一、安装Node.js官方网址:https://nodejs.org/zh-cn追求系统稳定性、可靠性以及希望减少维护频率的用户来说,LTS版…

【Kubernetes】集群启动nginx,观察端口映射,work节点使用kubectl配置

参考b站叩丁狼总结:完整版Kubernetes(K8S)全套入门微服务实战项目,带你一站式深入掌握K8S核心能力 在master节点执行 kubectl create deployment nginx --imagenginxkubectl expose deployment nginx --port80 --typeNodePort1. …

20250704-基于强化学习在云计算环境中的虚拟机资源调度研究

基于强化学习在云计算环境中的虚拟机资源调度研究 随着云计算规模的持续扩大,数据中心虚拟机资源调度面临动态负载、异构资源适配及多目标优化等挑战。传统启发式算法在复杂场景下易陷入局部最优,而深度强化学习(DRL)凭借序贯决策…

day 33打卡

day 21 常见的降维算法 # 先运行之前预处理好的代码 import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns import warnings warnings.filterwarnings(ignore)# 设置中文字体 plt.rcParams[font.sans-serif] [SimHei] plt.rcParam…

sec(x)积分推导

在MATLAB中绘制 sec⁡(x)、cos(x) 和 ln⁡∣sec⁡(x)tan⁡(x)∣的函数图像,需要特别注意 sec⁡(x) 在 cos⁡(x)0(即 xπ/2kπ)处的奇点。(deepseek生成代码)% 定义x范围(-2π到2π),…