SQL 外连接

devtools/2024/11/14 19:04:46/

 1 外连接

外连接是一种用于结合两个或多个表的方式,返回至少一个表中的所有记录。

左外连接

LEFT JOIN,左表为驱动表,右表为从表。返回驱动表的所有记录以及从表中的匹配记录。如果从表没有匹配,则结果中从表的部分为NULL。

右外连接

RIGHT JOIN,右表为驱动表,左表为从表。

全外连接

返回左右表中的所有记录,如果某侧表没有匹配,另一侧的结果为NULL。

表 外连接的三种类型

1.1 实践

1.1.1 行->列的转换:制作交叉表

图 课程信息t_courses表及期望输出

需求:O表示已学过,NULL表示尚未学习,利用课程表生成上面的交叉表。

-- 左连接
SELECT c1.name,
CASE WHEN c2.`name` IS NULL THEN NULL ELSE 'O' END AS 'SQL入门',
CASE WHEN c3.`name` IS NULL THEN NULL ELSE 'O' END AS 'UNIX基础',
CASE WHEN c4.`name` IS NULL THEN NULL ELSE 'O' END AS 'Java中级'
FROM (SELECT DISTINCT `name` FROM t_courses) c1
LEFT JOIN (SELECT `name` FROM t_courses WHERE course = 'SQL入门') c2 ON c1.name = c2.name 
LEFT JOIN (SELECT `name` FROM t_courses WHERE course = 'UNIX基础') c3 ON c1.name = c3.name 
LEFT JOIN (SELECT `name` FROM t_courses WHERE course = 'Java中级') c4 ON c1.name = c4.name 

上面代码比较直观和易于理解,但是大量用到了内嵌视图和连接操作,代码显得很臃肿。而且随着表头列数的增加,性能也会恶化。

一般情况下,外连接都可以用标量子查询替代。

-- 标量子查询
SELECT c.name,
(SELECT 'O' FROM t_courses WHERE `name` = c.name AND course = 'SQL入门') AS 'SQL入门',
(SELECT 'O' FROM t_courses WHERE `name` = c.name AND course = 'UNIX基础') AS 'UNIX基础',
(SELECT 'O' FROM t_courses WHERE `name` = c.name AND course = 'Java中级') AS 'Java中级'
FROM (SELECT DISTINCT `name` FROM t_courses) c; 

标量子查询(或者关联子查询),性能开销还是相当大的,因为其是针对SELECT返回的每一行来执行的。

-- 嵌套使用CASE表达式 
SELECT `name`,
CASE WHEN SUM(CASE WHEN course = 'SQL入门' THEN 1 ELSE 0 END) = 1 THEN 'O' else NULL END AS 'SQL入门',
CASE WHEN SUM(CASE WHEN course = 'UNIX基础' THEN 1 ELSE 0 END) = 1 THEN 'O' else NULL END AS 'UNIX基础',
CASE WHEN SUM(CASE WHEN course = 'Java中级' THEN 1 ELSE 0 END) = 1 THEN 'O' else NULL END AS 'Java中级'
FROM t_courses 
GROUP BY `name`;

1.1.2 列 -> 行的转换:汇总重复项于一列

图 员工个人信息t_personnel表及期望输出

-- 将列数据转换成行数据,使用UNION
SELECT employee,child_1 as child
FROM t_personnel
UNION
SELECT employee,child_2
FROM t_personnel
UNION
SELECT employee,child_3
FROM t_personnel;

表 使用UNION后的效果

但是像“铃木 NULL、工藤 NULL”这样的数据不希望输出,而”宫田 NULL”这样的数据要输出(他名下没有孩子,但是输出报表的时候,不能丢失这个员工信息)。

-- LEFT JOIN ... ON ...IN... 
SELECT p.employee,c.child
FROM t_personnel p
left join (SELECT *FROM (SELECT child_1 AS childFROM t_personnelUNION SELECT child_2 AS childFROM t_personnelUNIONSELECT child_3 AS childFROM t_personnel) tempWHERE child IS NOT NULL
) c ON c.child IN (p.child_1,p.child_2,p.child_3);

这样用了左连接,同时连接条件用了“IN”。

1.1.3 在交叉表里制作嵌套式表侧栏

图 年龄段t_age_class、性别类别t_sex、人口t_population表及期望输出

SELECT a.age_range,s.sex,p.area1 AS '东北',p.area2 AS '关东'
FROM 
(
SELECT age_class,sex_cd,
SUM(CASE WHEN area IN ('秋田','青森') THEN population ELSE NULL END) AS area1,
SUM(CASE WHEN area IN ('东京','千叶') THEN population ELSE NULL END) AS area2
FROM t_population
GROUP BY age_class,sex_cd
) p 
RIGHT JOIN t_age_class a ON a.age_class = p.age_class
RIGHT JOIN t_sex s ON s.sex_cd = p.sex_cd;

上面代码会导致31岁~40岁这个年龄段丢失。

图 输出结果

应当将t_age_class 与 t_sex 先进行连接。

SELECT a.age_range,s.sex,
SUM(CASE WHEN p.area IN ('秋田','青森') THEN p.population ELSE NULL END) AS '东北',
SUM(CASE WHEN p.area IN ('东京','千叶') THEN p.population ELSE NULL END) AS '关东'
FROM t_age_class a 
CROSS JOIN t_sex s
LEFT JOIN t_population p ON p.age_class = a.age_class AND p.sex_cd = s.sex_cd
GROUP BY a.age_class,s.sex;

1.1.4 作为乘法运算的连接

图 商品信息t_items、商品销量信息t_sales_history表及期望输出

SELECT i.item_no,SUM(quantity) AS quantity
FROM t_items i 
LEFT JOIN t_sales_history s ON s.item_no = i.item_no
GROUP BY i.item_no;

1.1.5 将两张表汇总到一张表

图 两张待融合的表

需求:将t_table_2 的数据全部融合到t_table_1,要求,id相同,则对t_table_1进行更新,否则进行插入。

图 融合后的t_table_1表

-- t_table_1 的主键为id
INSERT INTO t_table_1(id,`name`) 
SELECT id,`name`
FROM t_table_2
ON DUPLICATE KEY 
UPDATE `name` = VALUES(`name`);

http://www.ppmy.cn/devtools/133983.html

相关文章

Flutter:Dio下载文件到本地

import dart:io; import package:dio/dio.dart;main(){// 创建dio对象final dio Dio();// 下载地址var url https://*******.org/files/1.0.0.apk;// 手机端路径String savePath Directory.systemTemp.path/ceshi.apk;print(savePath);downLoad(dio,url,savePath); }downLo…

【excel基本操作-sumif绝对引用和相对引用

低量级数据的存储 复杂且无法优化的数据报表 怎么学excel? 一、输入与输出 二、计算与处理 三、可视化 四、连接匹配与自动化 excel操作笔记 打开表格第一步筛选 所以筛选的快捷键:shiftctrll 排序:多列排序 开始-排序与筛选-自定义排序-设置关键字添…

pytorch torch.tile用法

指定各维度分别重复多少次 tile 是 PyTorch 中用于重复张量的函数。它可以沿指定的维度重复张量的元素。以下是一个示例代码,展示 tile 的用法: import torch# 创建一个张量 weight_hh torch.tensor([[1, 2], [3, 4]])# 假设批量大小为3 bs 3# 使用 …

【C语言刷力扣】58.最后一个单词的长度

题目: 解题思路; 倒序遍历,先将末尾的空格过滤,再统计至第一个空格。 条件i > 0 放在前面先判断,条件s[i] ! 放后面,反之遇到单字符会溢出。 时间复杂度: 空间复杂度: int lengthOfLas…

2025年PMP的考纲是怎样的?又改版了吗?

2025年考纲没有变动,但是参考教材变了,不再使用《PMBOK》第六版作为参考教材了,改成了《过程组:实践指南》这本书,跟《PMBOK》第七版一起作为参考资料。 看到是不是很懵,感觉变化很大,其实《过程…

vue中setup语法糖的优点

Vue中的setup语法糖具有以下优点: 简化代码结构:setup语法糖使得组件内部逻辑更加简洁,将组件的配置和逻辑分离,使代码更易于维护和理解。更好的组件封装:使用setup语法糖,可以将组件的逻辑和状态封装在一…

读取文件内容、修改文件内容、识别文件夹目录(Web操作系统文件/文件夹详解)

前言 因 Unicode IDE 编辑器导入文件、文件夹需要,研究了下导入文件/文件夹的功能实现,发现目前相关文章有点少,故而记录下过程,如果有误,还望指正。(API的兼容性及相关属性、接口定义,请自行查看文件系统 …

分享一些Kafka集群优化的最佳实践?

以下是一些 Kafka 集群优化的最佳实践: 复制策略配置: 在 server.properties 文件中配置 default.replication.factor 来指定每个主题的默认副本因子,以及 min.insync.replicas 来配置每个分区中必须要保持同步的最小副本数。这可以提高 Kafk…