SQL 中的 EXISTS
EXISTS 的作用是:只要子查询能查到至少一条记录,就返回真。外层查询的每一行都会代入子查询中进行判断。
-- 查找有对应班级的学生
SELECT * FROM student s
WHERE EXISTS (
SELECT * FROM Classx c WHERE c.ID = s.ClassID
)
逐步理解:
| 学生 | ClassID | 子查询 SELECT * FROM Classx WHERE ID = ? | 结果 |
|---|---|---|---|
| 张三 | 1 | 能查到 ID=1 的班级 | 显示 |
| 李四 | 5 | 能查到 ID=5 的班级 | 显示 |
| 周七 | 9 | 查不到 ID=9 的班级 | 不显示 |
LINQ 中的等效写法
在 LINQ 中,使用 Any() 方法实现 EXISTS 语义。Any() 返回 bool,表示序列中是否存在满足条件的元素。
using (var db = new DataClasses1DataContext())
{
var q = from s in db.Student
where db.Classx.Any(m => m.ID == s.ClassID)
select s;
var res = q.ToList();
}Code language: JavaScript (javascript)
方法语法等效写法:
var res = db.Student
.Where(s => db.Classx.Any(m => m.ID == s.ClassID))
.ToList();Code language: JavaScript (javascript)
生成的 SQL
SELECT [t0].[ID], [t0].[Name], [t0].[ClassID], [t0].[AddTime], [t0].[Status]
FROM [dbo].[Student] AS [t0]
WHERE EXISTS (
SELECT NULL AS [EMPTY]
FROM [dbo].[Classx] AS [t1]
WHERE ([t1].[ID]) = [t0].[ClassID]
)Code language: PHP (php)
可以看到,LINQ 的
Any()直接翻译为 SQL 的EXISTS子查询,在数据库端执行,不会全表加载到内存。
Any() 的多种用法
| 场景 | 写法 | 说明 |
|---|---|---|
| 带条件(等效 EXISTS) | db.Classx.Any(m => m.ID == s.ClassID) | 子查询有匹配则返回 true |
| 无条件(永远为 true) | db.Classx.Any() | 等效 EXISTS (SELECT * FROM Classx),永远返回真 |
| 判断集合非空 | list.Any() | 不查询数据库,判断内存集合是否有元素 |
| 带复杂条件 | db.Classx.Any(m => m.ID == s.ClassID && m.Name.Contains("实验")) | 多条件 EXISTS |
EXISTS 与 IN 的对比
EXISTS 写法:
SELECT * FROM student s
WHERE EXISTS (SELECT 1 FROM Classx c WHERE c.ID = s.ClassID)
IN 写法:
SELECT * FROM student s
WHERE s.ClassID IN (SELECT ID FROM Classx)Code language: CSS (css)
LINQ 中两种写法对比:
// EXISTS 风格(推荐,可走索引)
var q1 = from s in db.Student
where db.Classx.Any(m => m.ID == s.ClassID)
select s;
// IN 风格
var classIds = db.Classx.Select(c => c.ID).ToList();
var q2 = from s in db.Student
where classIds.Contains(s.ClassID)
select s;Code language: JavaScript (javascript)
| 对比项 | EXISTS (Any) | IN (Contains) |
|---|---|---|
| SQL 生成 | EXISTS (...) 子查询 | IN (...) 或参数列表 |
| 性能 | 通常更优,可用索引 | 值多时参数膨胀 |
| 写法 | 一步完成 | 需先查 ID 列表 |
| 推荐 | 关联判断首选 | 简单值列表判断 |
Previous: 外连接的两种 LINQ 写法