结果集差集(Except)

核心概念

Except差集——返回在第一个集合中但不在第二个集合中的元素。等效于 SQL 中的 EXCEPT(或 MINUS)。

Intersect 的区别:Intersect共同部分Except第一个集合独有的部分


LINQ 中的写法

using (var db = new DataClasses1DataContext())
{
    // q1: ID < 3 → 1, 2
    var q1 = from s in db.Student
             where s.ID < 3
             select s;

    // q2: ID < 5 → 1, 2, 3, 4
    var q2 = from s in db.Student
             where s.ID < 5
             select s;

    // q1 中有但 q2 中没有的
    var r = q1.Except(q2).ToList();   // 结果:空(q1 全部在 q2 中)

    // q2 中有但 q1 中没有的
    var r2 = q2.Except(q1).ToList();  // 结果:ID = 3, 4
}Code language: JavaScript (javascript)

执行结果示意

操作含义结果
q1.Except(q2){1, 2} − {1, 2, 3, 4}
q2.Except(q1){1, 2, 3, 4} − {1, 2}{3, 4}

顺序敏感:Except 不是对称的,A.Except(B)B.Except(A)


生成的 SQL

q1.Except(q2) 生成的 SQL(类似 Intersect,使用 NOT EXISTS 子查询):

SELECT [t0].[ID], [t0].[Name], [t0].[ClassID], [t0].[AddTime], [t0].[Status]
FROM [dbo].[Student] AS [t0]
WHERE ([t0].[ID] < 3)
  AND NOT EXISTS (
    SELECT NULL AS [EMPTY]
    FROM [dbo].[Student] AS [t1]
    WHERE ([t1].[ID] < 5) AND ([t0].[ID] = [t1].[ID])
  )Code language: PHP (php)

逻辑:从 q1 的结果中排除掉那些在 q2 中能找到的记录。


不同表取差集

// 有客户但没有员工的 Country
var q = (from c in db.Customers
         select c.Country)
        .Except(
         from e in db.Employees
         select e.Country
        );Code language: JavaScript (javascript)

三个集合操作的完整对比

操作LINQ 方法SQL 等效说明是否去重
并集Union()UNION合并 + 去重
合并不去重Concat()UNION ALL直接拼接
交集Intersect()INTERSECT共同部分
差集Except()EXCEPT第一个有、第二个没有

关键要点

要点说明
顺序敏感A.Except(B)B.Except(A)
自动去重结果集自动 DISTINCT
类型要求两边元素类型必须一致
执行位置IQueryable 调用 → 数据库端 NOT EXISTS;对 List 调用 → 内存操作
常见用途查找”新增的”、”被删除的”、”独有的”记录

典型场景:​ 对比两个时间点的数据差异——today.Except(yesterday) 找出新增的,yesterday.Except(today) 找出删除的。


集合操作速查

A.Union(B)      // A + B(去重)
A.Concat(B)     // A + B(不去重)
A.Intersect(B)  // A ∩ B
A.Except(B)     // A − BCode language: PHP (php)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注