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