SQL 实战:联合查询与子查询 – 数据比对与关联查询优化

在复杂的数据分析和开发场景中,我们经常需要对多张表的数据进行比对和关联查询,以满足复杂业务需求。SQL 提供了丰富的查询方式,包括 JOINUNION 和子查询,这些技术在处理多表关联、交叉比对以及过滤特定数据时非常高效。

本文将详细介绍 JOINUNION 和子查询 的核心用法,并通过实际案例展示如何利用这些方法进行数据比对与查询优化。


一、核心概念与区别

1. JOIN(连接查询)

JOIN 主要用于多表之间的行级数据关联,可以根据相关字段将多张表的数据合并在一起。

  • INNER JOIN:返回两张表中符合匹配条件的记录。
  • LEFT JOIN:返回左表的所有记录,如果右表没有匹配,返回 NULL
  • RIGHT JOIN:返回右表的所有记录,如果左表没有匹配,返回 NULL
  • FULL JOIN(部分数据库支持):返回两张表中所有匹配和不匹配的记录。

示例

SELECT *  
FROM orders o  
INNER JOIN customers c  
ON o.customer_id = c.customer_id;

2. UNION(合并查询)

UNION 将多次 SELECT 查询的结果合并到一起,返回去重后的记录。

  • UNION ALL:合并结果但不去重,性能更高。

示例

SELECT name FROM employees  
UNION  
SELECT name FROM managers;

3. 子查询(Subquery)

子查询是一种嵌套查询,可以在 SELECTFROMWHERE 等语句中使用,通常用于复杂的条件筛选或分层查询。

  • EXISTS / NOT EXISTS:判断子查询结果是否存在,适合在关联过滤中使用。
  • IN / NOT IN:用于判断某字段是否在子查询结果集范围内。

示例

SELECT name FROM customers  
WHERE customer_id IN (SELECT customer_id FROM orders WHERE amount > 1000);

二、实战案例:复杂数据比对与关联查询


案例 1:查询购买过商品 A 但未购买商品 B 的用户

场景
电商系统中,用户可以购买不同的商品。我们希望找出购买了商品 A 但从未购买商品 B 的用户,以便进行针对性的营销活动。


表结构
  • users:用户表
    | user_id | name |
    |---------|-------|
    | 1 | 张三 |
    | 2 | 李四 |
    | 3 | 王五 |

  • orders:订单表
    | order_id | user_id | product_name |
    |----------|---------|--------------|
    | 101 | 1 | 商品A |
    | 102 | 2 | 商品B |
    | 103 | 1 | 商品C |
    | 104 | 3 | 商品A |
    | 105 | 3 | 商品B |


方法 1:使用 LEFT JOIN + NULL 判断
SELECT u.user_id, u.name  
FROM users u  
LEFT JOIN orders a ON u.user_id = a.user_id AND a.product_name = '商品A'  
LEFT JOIN orders b ON u.user_id = b.user_id AND b.product_name = '商品B'  
WHERE a.order_id IS NOT NULL  AND b.order_id IS NULL;

结果

user_idname
1张三

解释

  • 第一个 LEFT JOIN 过滤出购买过商品 A 的用户。
  • 第二个 LEFT JOIN 尝试关联商品 B,如果为空表示未购买。
  • 使用 WHERE b.order_id IS NULL 过滤出未购买商品 B 的用户。

方法 2:使用 NOT EXISTS 子查询
SELECT u.user_id, u.name  
FROM users u  
WHERE EXISTS (SELECT 1 FROM orders o  WHERE o.user_id = u.user_id AND o.product_name = '商品A'  
)  
AND NOT EXISTS (SELECT 1 FROM orders o  WHERE o.user_id = u.user_id AND o.product_name = '商品B'  
);

结果

user_idname
1张三

解释

  • EXISTS 子查询 确认用户购买过商品 A。
  • NOT EXISTS 子查询 过滤掉购买过商品 B 的用户。

方法 3:使用 NOT IN 子查询
SELECT u.user_id, u.name  
FROM users u  
WHERE u.user_id IN (SELECT user_id FROM orders WHERE product_name = '商品A'  
)  
AND u.user_id NOT IN (SELECT user_id FROM orders WHERE product_name = '商品B'  
);

结果

user_idname
1张三

解释

  • 使用 INNOT IN 简单直接,适合小数据量场景。
  • 适用于数据量不大时,IN 查询的执行速度较快。

三、复杂多表关联与优化技巧

案例 2:查询每个用户的购买总额和订单数量

需求:统计每个用户的总购买金额和订单数量,列出用户的订单汇总信息。


SQL 实现
SELECT u.user_id, u.name,  COUNT(o.order_id) AS total_orders,  SUM(o.amount) AS total_amount  
FROM users u  
LEFT JOIN orders o ON u.user_id = o.user_id  
GROUP BY u.user_id, u.name  
ORDER BY total_amount DESC;

解释

  • 使用 LEFT JOIN 确保即使用户没有订单记录,也能在统计中体现。
  • GROUP BY 进行分组统计,每个用户作为一组计算订单数量和总金额。

四、关联查询优化技巧

  1. 避免嵌套子查询
  • 将嵌套子查询改写为 JOIN,减少重复扫描表的次数。
  • 在大数据量场景中,JOIN 通常比子查询性能更优。

优化示例

-- 子查询方式(低效)
SELECT name FROM users  
WHERE user_id IN (SELECT user_id FROM orders WHERE amount > 500);  -- JOIN 优化方式
SELECT DISTINCT u.name  
FROM users u  
JOIN orders o ON u.user_id = o.user_id  
WHERE o.amount > 500;
  1. 使用 EXISTS 替代 IN
    EXISTSIN 更适合大数据量查询,因为 EXISTS 一旦匹配到结果就返回,不需要扫描完整表。
SELECT name FROM users u  
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.user_id AND o.amount > 500
);
  1. 索引优化
  • 在关联字段和过滤字段上建立索引,提升 JOIN 和子查询的执行速度。
CREATE INDEX idx_orders_user_id ON orders(user_id);

五、总结

  • JOIN 适用于多表关联,子查询适用于复杂的条件筛选
  • EXISTSNOT EXISTS 在处理数据比对时非常高效,适合大数据量关联过滤。
  • 使用 LEFT JOIN + NULL 判断 是解决差集问题的常用方式。
  • 在实际项目中,合理选择 JOINUNION 和子查询可以显著提升查询效率。

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

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

相关文章

HTML——13.超链接

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>超链接</title></head><body><!--超链接:从一个网页链接到另一个网页--><!--语法&#xff1a;<a href"淘宝网链接的地址"> 淘宝…

LVS 负载均衡原理 | 配置示例

注&#xff1a;本文为 “ LVS 负载均衡原理 | 配置” 相关文章合辑。 部分内容已过时&#xff0c;可以看看原理实现。 使用 LVS 实现负载均衡原理及安装配置详解 posted on 2017-02-12 14:35 肖邦 linux 负载均衡集群是 load balance 集群的简写&#xff0c;翻译成中文就是负…

Docker 快速搭建 GBase 8s数据库服务

1.查看Gbase 8s镜像版本 可以去到docker hub网站搜索&#xff1a;gbase8s liaosnet/gbase8s如果无法访问到该网站&#xff0c;可以通过docker search搜索 docker search gbase8s2.拉取Gbase 8s镜像 以下演示的版本是目前官网最新版本Gbase8sV8.8_3.5.1 docker pull liaosn…

使用Lodash工具库的orderby和sortby进行排序的区别

简介 _.orderBy 和 _.sortBy 是 Lodash 库中用于排序数组的两个函数。 区别 _.orderBy 允许你指定一个或多个属性来排序&#xff0c;并为每个属性指定排序方向&#xff08;升序或降序&#xff09;。默认所有值为升序排&#xff0c;指定为"desc" 降序&#xff0c…

uniapp中Nvue白屏问题 ReferenceError: require is not defined

uniapp控制台输出如下 exception function:createInstanceContext, exception:white screen cause create instanceContext failed,check js stack ->Uncaught ReferenceError: require is not defined 或者 exception function:createInstanceContext, exception:white s…

STM32-笔记16-定时器中断点灯

一、实验目的 使用定时器 2 进行中断点灯&#xff0c;500ms LED 灯翻转一次。 二&#xff0c;定时器溢出时间计算 Tout&#xff1a;定时器溢出时间 Ft&#xff1a;定时器的时钟源频率 ARR&#xff1a;自动重装载寄存器的值&#xff08;可设置ARR从0开始&#xff0c;但是计数到…

Visual Studio 使用 GitHub Copilot 与 IntelliCode 辅助编码 【AI辅助开发系列】

&#x1f380;&#x1f380;&#x1f380;【AI辅助编程系列】&#x1f380;&#x1f380;&#x1f380; Visual Studio 使用 GitHub Copilot 与 IntelliCode 辅助编码Visual Studio 安装和管理 GitHub CopilotVisual Studio 使用 GitHub Copilot 扩展Visual Studio 使用 GitHu…

【数据结构】数据结构整体大纲

数据结构用来干什么的&#xff1f;很简单&#xff0c;存数据用的。 &#xff08;这篇文章仅介绍数据结构的大纲&#xff0c;详细讲解放在后面的每一个章节中&#xff0c;逐个击破&#xff09; 那为什么不直接使用数组、集合来存储呢 ——> 如果有成千上亿条数据呢&#xff…

开放世界目标检测 Grounding DINO

开放世界目标检测 Grounding DINO flyfish Grounding DINO 是一种开创性的开放集对象检测器&#xff0c;它通过结合基于Transformer的检测器DINO与基于文本描述的预训练技术&#xff0c;实现了可以根据人类输入&#xff08;如类别名称或指代表达&#xff09;检测任意对象的功…

webrtc 源码阅读 make_ref_counted模板函数用法

目录 1. 模板参数解析 1.1 typename T 1.2 typename... Args 1.3 typename std::enable_if::value, T>::type* nullptr 2. scoped_refptr 3. new RefCountedObject(std::forward(args)...); 4. 综合说明 5.在webrtc中的用法 5.1 peerConnectionFactory对象的构建过…

RK3566和Robo_C的EMC防护设计细节

USB部分的防护细节&#xff1a; ROBO C的USB接口&#xff1a; PF级别的电容滤波&#xff1a; TVS电容&#xff08;TVS Capacitor&#xff09;&#xff1a;用于与TVS二极管配合&#xff0c;保护电路免受瞬态电压冲击。电容一般较小&#xff0c;通常为几十皮法&#xff08;pF&am…

如果你的网站是h5网站,如何将h5网站变成小程序-除开完整重做方法如何快速h5转小程序-h5网站转小程序的办法-优雅草央千澈

如果你的网站是h5网站&#xff0c;如何将h5网站变成小程序-除开完整重做方法如何快速h5转小程序-h5网站转小程序的办法-优雅草央千澈 h5如何转小程序 如果当年你们开发网站是用的h5但是没有开发小程序&#xff0c;也没有使用uniapp这样的混开框架&#xff0c;但是目前根据业务需…

30天面试打卡计划 2024-12-25 26 27 面试题

2024-12-25 面试题 后端 MySQL三层B树能存多少数据&#xff1f; B 树&#xff1a;一种特殊的多路平衡查找树&#xff0c;广泛应用于数据库索引中。它具有所有叶子节点都位于同一层且包含指向相邻叶子节点指针的特点&#xff0c;这使得范围查询更加高效。InnoDB&#xff1a;My…

微信流量主挑战:用户破16!新增文档转换(新纪元3)

朋友们&#xff0c;报告好消息&#xff01;我的小程序用户数量已经涨到16个了&#xff01;没错&#xff0c;真没拉朋友圈亲戚好友来撑场子&#xff0c;全靠实力&#xff08;和一点点运气&#xff09;吸引了16位陌生小伙伴光临&#xff01;这波进步&#xff0c;连我自己都感动了…

阿里云redis内存优化——PCP数据清理

在阿里云安装了一个redis节点&#xff0c;今天使用时忽然想着点击了一下分析内存。好家伙&#xff0c;居然崩出了一个30多M的块出来。问题是我本地安装的redis没有这个啊&#xff0c;怎么奇怪冒出这个来了。 本着把系统用干榨尽的态度&#xff0c;研究了下这个问题的来源。网上…

常见的排序算法过程和比较分析

比较分析 排序类别排序算法时间复杂度&#xff08;最好&#xff09;时间复杂度&#xff08;最坏&#xff09;时间复杂度&#xff08;平均&#xff09;辅助空间复杂度稳定性插入排序直接插入排序O(n)O(n)O(n)O(1)稳定插入排序折半插入排序O(n)O(n)O(n)O(1)稳定插入排序希尔排序…

webrtc-internals调试工具

Google 的 Chrome&#xff08;87 或更高版本&#xff09;WebRTC 内部工具是一套内置于 Chrome 浏览器中的调试工具; webrtc-internals 能够查看有关视频和音频轨道、使用的编解码器以及流的一般质量的详细信息。这些知识对于解决音频和视频质量差的问题非常有帮助。 webrtc-int…

VS Code中怎样查看某分支的提交历史记录

VsCode中无法直接查看某分支的提交记录&#xff0c;需借助插件才行&#xff0c;常见的插件如果git history只能查看某页面的改动记录&#xff0c;无法查看某分支的整体提交记录&#xff0c;我们可以安装GIT Graph插件来解决这个问题 1.在 VSCode的插件库中搜索 GIT Graph安装&a…

超详细!一文搞定PID!嵌入式STM32-PID位置环和速度环

本文目录 一、知识点1. PID是什么&#xff1f;2. 积分限幅--用于限制无限累加的积分项3. 输出值限幅--用于任何pid的输出4. PID工程 二、各类PID1. 位置式PID&#xff08;用于位置环&#xff09;&#xff08;1&#xff09;公式&#xff08;2&#xff09;代码使用代码 2. 增量式…

学习solid works第八课------工程图

一、新建工程图 工程图创建不像零件和装配体一样直接点击新建&#xff0c;工程图跟零件的关联在一起的&#xff0c;我们需要需要先打开零件&#xff0c;在零件中建立对应的工程图。 1. 打开需要做工程图的零件&#xff08;以一颗螺丝为例子&#xff09;。 2. 在文件下拉菜单中…