Mysql查询某一字段A表存在但B表不存在的新增数据


问题描述

昨天在面试中遇到了这样一个问题:

假如aa表中存在XX字段,bb表中存在XX字段,要求使用最快的sql找出存在aa表中但不存在bb表中的数据,请说明原因为什么认为它最快

问题分析

根据问题,立马回想起了以前的一个项目,这不就是找新增数据嘛,见下图:
image

绿色就代表新增数据了,红色代表join数据,很显然题中是只需要绿色部分的新增数据即可;
然而left join会查询出红色+绿色;而inner join只能查询出红色;
left join结果 - inner join结果就好了,这是最原始的想法,也是最笨的思路,显然要丢弃

解决方案

既然打算实验,那就先创建两张表吧!

部门表

-- ----------------------------
-- Table structure for department
-- ----------------------------
DROP TABLE IF EXISTS `department`;
CREATE TABLE `department`  (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '表ID字段',
  `dept` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '部门',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of department
-- ----------------------------
INSERT INTO `department` VALUES (1, '开发部');
INSERT INTO `department` VALUES (2, '测试部');
INSERT INTO `department` VALUES (3, '其他部');
INSERT INTO `department` VALUES (4, '数据部');

新部门表

-- ----------------------------
-- Table structure for new_department
-- ----------------------------
DROP TABLE IF EXISTS `new_department`;
CREATE TABLE `new_department`  (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '自增ID',
  `dept` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '部门',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of new_department
-- ----------------------------
INSERT INTO `new_department` VALUES (1, '开发部');
INSERT INTO `new_department` VALUES (2, '测试部');
INSERT INTO `new_department` VALUES (3, '财务部');
INSERT INTO `new_department` VALUES (4, '运营部');
INSERT INTO `new_department` VALUES (5, '市场部');
INSERT INTO `new_department` VALUES (6, '数据部');

说明:为了简化,以下用a表代表new_department; b表代表department

方案一

-- 1、找到b表中所有的dept
-- 2、找到a表中所有的dept
-- 3、使用not in进行排除重复数据
SELECT
	* 
FROM
	new_department a
WHERE
	dept NOT IN ( SELECT dept FROM department b);

效率最低,不做解释了

image

方案二

-- 1、a表左连接b表,可以查出所有部门信息(可以查看效果)
-- 2、判断条件:b表的dept为空,即能查询出新增数据
SELECT
	* 
FROM
	new_department a
	LEFT JOIN department b ON a.dept = b.dept 
WHERE
	b.dept IS NULL;

左连接效果:

image

效率比not in要快上一些,至少两条语句都是简单查询

image

方案三

-- sql执行顺序
-- from => where => group by => having => order => select
-- 1、统计a表和b表连接的行数,连接字段:dept
-- 2、子查询的行数为0,即能查询出新增数据
SELECT
	* 
FROM
	new_department a 
WHERE
	( SELECT count( 1 ) FROM department b WHERE a.dept = b.dept ) = 0;

使用数字比较,也比not in要快,至于方案二和方案三谁快,就需要进行大量试验了

image

方案三分析

参考了https://zhidao.baidu.com/question/509144661.html中第二条评论

先来查看一下a表和b表的所有数据吧

department表数据(b表)

SELECT * FROM new_department;

image

new_department表数据(a表)

SELECT * FROM department;

image


select * from new_department是执行a表

  1. 当执行“dept=开发部”时 ,执行select count(1) from department b where a.dept = b.dept,因为a表和b表都有"开发部",结果不等于0,所以运行结果没有第一行“dept=开发部”;

  2. 当执行“dept=测试部”时 ,执行select count(1) from department b where a.dept = b.dept ,因为a表和b表都有"测试部",结果不等于0,所以运行结果没有第二行“dept=测试部”;

  3. 当执行“dept=财务部”时 ,执行select count(1) from department b where a.dept = b.dept ,因为a表有"财务部"而b表没有"财务部",结果等于0 ,符合条件,所以被查询出来了;

  4. 其余依次类推,因此可以在a表中排除b表的数据,最终结果:

    image


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM