当前位置:首页 > 问答 > 正文

数据库里怎么找两个表不一样的数据差集,简单点说咋操作?

你问的这个问题,说白了就是:有两个表,长得挺像,比如都是员工信息表,但一个是去年的,一个是今年的,你想知道今年和去年比,到底多了哪些新员工,或者少了哪些离职的员工,这个“多出来的”和“少了的”部分,就是你说的“数据差集”。

在数据库里,干这个事儿最直接、最常用的方法就是用一个叫做 NOT EXISTS 的家伙,我给你打个比方,你就明白了。

想象一下,你有两份名单,A名单和B名单,你想找出“在A名单里,但不在B名单里”的人,你怎么找?你可能会拿着A名单,一个人名一个人名地去B名单里核对,如果在B名单里找不到这个人,那这个人就是你要找的“差集”。

NOT EXISTS 干的就是这个核对的工作,它的工作方式就是:“给我一条A表的数据,我去B表里搜一圈,如果我在B表里找不到符合条件的数据,那么我就把A表这条数据留下来。”

具体到操作上,假设你有两个表:

  • table_old (去年的员工表),里面有字段 id, name。
  • table_new (今年的员工表),里面也有字段 id, name。

找出离职的员工(在旧表里有,但在新表里没有了)

你的SQL语句会这么写:

SELECT old.id, old.name
FROM table_old old
WHERE NOT EXISTS (
    SELECT 1
    FROM table_new new
    WHERE new.id = old.id
);

我来一句句解释一下,保证你都能看懂:

  1. SELECT old.id, old.name: 这表示我最终想看到的结果是显示旧表里的员工ID和姓名。
  2. FROM table_old old: 从旧表里取数据,我给table_old起了个简短的外号叫old,这样后面写起来方便。
  3. WHERE NOT EXISTS (...): 这是最关键的部分,意思是“只要满足后面括号里条件‘不成立’的数据”。
  4. (SELECT 1 FROM table_new new WHERE new.id = old.id): 这个括号里的子查询就是“核对”的过程,它的意思是:“去新表(我给它起外号叫new)里找,找什么呢?找一条记录,这条记录的id要和外面主查询里当前正在处理的那条旧表记录的id一样。” 这里的SELECT 1是个习惯写法,它不关心具体查出来什么数据,只关心“有没有找到”,找到就返回“真”,找不到就返回“假”。

整个语句连起来就是:遍历旧表里的每一个员工,拿着他的ID去新表里找有没有同样ID的员工,如果在新表里找不到(NOT EXISTS),说明这个员工离职了,就把他的信息显示出来。

数据库里怎么找两个表不一样的数据差集,简单点说咋操作?

找出新入职的员工(在新表里有,但在旧表里没有了)

这个和上面的道理一模一样,只是把两个表调换一下位置就行了。

SELECT new.id, new.name
FROM table_new new
WHERE NOT EXISTS (
    SELECT 1
    FROM table_old old
    WHERE old.id = new.id
);

这个语句的意思是:遍历新表里的每一个员工,拿着他的ID去旧表里找有没有同样ID的员工,如果在旧表里找不到,说明这个员工是新来的,就把他的信息显示出来。

除了NOT EXISTS,还有别的方法吗?

有,还有一个叫 LEFT JOIN ... WHERE ... IS NULL 的方法,也挺常用的,我也顺便说一下,你自己看哪个更好理解。

数据库里怎么找两个表不一样的数据差集,简单点说咋操作?

还是用找“离职员工”的例子:

SELECT old.id, old.name
FROM table_old old
LEFT JOIN table_new new ON old.id = new.id
WHERE new.id IS NULL;

这个方法的思路不一样,它是这样的:

  1. FROM table_old old LEFT JOIN table_new new ON old.id = new.id: 我用“左连接”的方式把两个表拼起来,左连接的意思是:不管能不能匹配上,旧表(左边的表)的所有记录都必须保留,如果能用ID匹配上新表的数据,就把新表的那一行数据拼在旁边;如果匹配不上(说明这个人在新表里没有),那么新表那边的所有字段就都是空的(在数据库里叫NULL)。
  2. WHERE new.id IS NULL: 连接完成后,我只要那些“新表ID是空”的记录,这不就正好是“在旧表里有,但在新表里找不到匹配项”的记录吗?也就是离职员工。

这个方法也挺直观的,你可以把它想象成:先把两张表并排铺开,根据ID把能对上号的人连上线,连不上线的那些人,就是你要找的人。

简单点说咋操作:

  • 核心思想:拿着一张表的数据,去另一张表里“核对”是否存在。
  • 最推荐的方法:使用 NOT EXISTS,写法简单,意思直白,大多数情况下效率也很好。
    • 找A有B无:SELECT ... FROM A WHERE NOT EXISTS (SELECT 1 FROM B WHERE 关联条件)
    • 找B有A无:把A和B位置互换一下就行。
  • 另一个好方法:使用 LEFT JOIN ... WHERE ... IS NULL,先连接,再筛选出连接失败的数据。

对于刚接触数据库的人来说,NOT EXISTS的逻辑可能更容易第一步就想明白,你就记住那个“拿着名单一个个去核对”的画面就行了,这两种方法在大部分数据库(比如MySQL, PostgreSQL, SQL Server)里都能用,而且处理一般的数据量都很快。

最后提醒一点,无论用哪种方法,最关键的是那个“关联条件”,比如我例子里的old.id = new.id,你一定要找一个能唯一标识一条记录的字段来关联,比如员工ID、身份证号这种,如果你用姓名来关联,万一有两个重名的,结果就不准了。