SQL 通配符常用于模糊查询,主要配合 LIKE 和 NOT LIKE 使用。它是一组有特殊含义的占位字符,写在字符串条件中可以替代未知内容。不同数据库支持的通配符略有差异,但最核心的百分号和下划线几乎在所有数据库中都通用。

理解通配符时,首先要把它们和正则表达式区分开。SQL 通配符语法更简单,能力也更有限,设计目标是在 WHERE 条件中快速表达“以某串开头”“包含某串”“只差一个字符”这类需求。接下来从语法、性能、转义和方言差异几个角度展开。
一、LIKE 与通配符的基本语法
LIKE 是 SQL 中用于模式匹配的谓词,通常只和字符串类型字段配合使用。通配符可以嵌入到模式字符串中,与普通字符共同构成匹配规则。最常用的通配符有两个:% 和 _。其中 % 表示零个、一个或多个字符,类似正则中的 .*;_ 表示恰好一个字符。还有一些数据库扩展了方括号语法,例如 SQL Server 支持 [abc] 表示匹配 a、b、c 中的任意一个,[^abc] 表示匹配不是 a、b、c 的任意一个字符。MySQL 和 PostgreSQL 不直接支持方括号通配符。
下面先创建一张商品表,后续示例都围绕它展开:
-- 建表并插入示例数据
CREATE TABLE products (
id INT PRIMARY KEY,
product_name VARCHAR(100),
product_code VARCHAR(50)
);
INSERT INTO products VALUES
(1, '华为手机 Mate 60', 'HW-M60'),
(2, '华为手机 P60', 'HW-P60'),
(3, '小米手机 13', 'XM-13'),
(4, '苹果手机 15', 'AP-15'),
(5, '平板电脑', 'TB-01');
查询名称以“华为”开头的所有商品,可以写成 LIKE '华为%'。如果只想匹配编码中第二个字符为 M,并且总长度为 6 的编码,可以使用多个下划线,如 LIKE '_M____'。下划线在写代码时容易忘记数量,建议数清楚之后再执行,否则结果集会少一行或多一行。
二、% 和 _ 的选择逻辑与索引影响
通配符位置对性能的影响远大于通配符种类。B+树索引按照字符串从左到右排序,因此只有模式开头是确定字符时,优化器才能利用索引快速定位范围。以 product_name 列为例,如果经常执行 LIKE '华为%',索引可以定位到以“华为”开头的连续区间,这种叫前缀匹配。如果写成 LIKE '%手机%',由于目标字符串可能出现在字段的任意位置,索引无法缩小扫描范围,数据库只能逐行读取并比较。后缀匹配 LIKE '%手机' 同理。
实际执行计划里,前缀匹配通常显示 range 或 index range scan,而包含匹配往往显示全表扫描或全索引扫描。下面用三个查询对比说明:
-- 前缀匹配:通常能走索引 SELECT id, product_name FROM products WHERE product_name LIKE '华为%'; -- 后缀匹配:通常无法走索引 SELECT id, product_name FROM products WHERE product_name LIKE '%手机'; -- 包含匹配:通常无法走索引 SELECT id, product_name FROM products WHERE product_name LIKE '%手机%';
如果业务上经常需要后缀模糊查询,可以把字符串反转后存储到新列,再对反转列建立索引。例如要快速查找以“手机”结尾的商品,可以新增 reverse_name 列,查询时写 WHERE reverse_name LIKE '机手%'。这种反向索引方案适合数据量较大、后缀查询频繁的场景。如果是包含匹配,反向索引也帮不上忙,通常要引入全文索引或其他检索方案。
下划线同样影响索引,但通常用于固定格式的字段。比如某个编号固定格式为三位字母加四位数字,使用 LIKE 'HW-____' 可以精确限定长度。不过如果查询中把下划线放在开头,如 LIKE '__M60',索引一样会失效。因此关键不是选择 % 还是 _,而是尽量把确定字符放在模式最前面。也就是说,通配符出现在模式开头,远比选择哪种通配符更影响性能。
三、ESCAPE 转义与特殊字符处理
实际数据中经常包含百分号、下划线甚至方括号等字符。例如商品编码可能是 50%_DIscount,如果直接写 LIKE '50%_DIscount',% 会被解释为任意长度,_ 被解释为单个字符,导致结果不正确。这种场景就需要明确告诉数据库哪些通配符只是普通字符。
SQL 标准提供 ESCAPE 子句,允许指定一个转义字符。转义字符后面的通配符按普通字符处理。常见写法如下:
-- 使用 # 作为转义字符,查找包含 50%_Dark 字样的记录 SELECT product_code FROM products WHERE product_code LIKE '%50#%#_Dark%' ESCAPE '#'; -- SQL Server 示例:反斜杠不是字符串转义符,可以这样匹配路径 SELECT log_path FROM app_logs WHERE log_path LIKE 'C:\ASR\%' ESCAPE '\';
第二个例子中,ESCAPE '\' 指定反斜杠为转义字符,\% 才会匹配字面百分号,而不是任意长度字符。不同数据库对默认转义行为差异很大:MySQL 默认把反斜杠当作字符串转义符,SQL Server 通常需要显式 ESCAPE,PostgreSQL 默认没有转义通配符能力,但也可以用 ESCAPE。因此涉及跨数据库时,显式声明 ESCAPE 是最稳妥的做法。
如果数据中含有 [、] 等字符,在 SQL Server 中方括号默认作为字符集语法,查询字面方括号也需要用转义或方括号技巧。例如匹配左方括号可以写 LIKE '[[]%',可读性较差。此时更推荐借助 ESCAPE 配合转义字符处理。不要因为业务数据里暂时没有特殊字符就省略转义逻辑,后续数据变更后容易出现隐蔽的错误查询。
四、常见避坑建议与数据库差异
通配符查询里最容易踩的坑之一,是忽略 NULL。LIKE 不会匹配 NULL 值,即使模式是 %% 也不会返回 NULL 行。若需要包含 NULL,必须显式使用 OR 条件,例如 WHERE product_name LIKE '华为%' OR product_name IS NULL。
另一个常见误区是依赖通配符处理大小写。不同数据库默认排序规则不同,MySQL 中 utf8mb4_general_ci 一般不区分大小写,LIKE 'abc%' 也能匹配 ABC;PostgreSQL 默认区分大小写,LIKE 'abc%' 不会匹配 ABC,需要 ILIKE。设计查询前应先确认列的排序规则和业务预期。如果业务明确要求忽略大小写,优先选择数据库提供的 ILIKE 或统一转成小写再比较,但要注意函数可能让索引失效。
还有尾部空格问题。SQL Server 中字符串比较会忽略部分尾部空格,但 LIKE 对尾部空格可能敏感;MySQL 的 CHAR 和 VARCHAR 在比较时也可能自动补齐或忽略空格。遇到这类问题时,可以先使用 TRIM 函数处理,但要注意函数会让该列索引失效。更合理的做法是在写入阶段就清理好数据,避免把空格问题留给查询阶段。
从安全角度,模糊查询参数不能直接拼接用户输入,否则容易产生 SQL 注入或通配符注入。比如用户输入 % 或 _,如果直接拼进 LIKE,可能返回全表数据。正确做法是使用参数化查询,并在应用层对传入的百分号和下划线进行转义。不同数据库的通配符支持范围也不一样:
| 数据库 | LIKE 通配符 | 是否支持方括号 | 备注 |
|---|---|---|---|
| MySQL | % _ | 不支持 | 默认反斜杠转义,可用 ESCAPE 覆盖 |
| SQL Server | % _ [] [^] | 支持 | 方括号字符集,需注意转义 |
| PostgreSQL | % _ | 不支持 | 区分大小写,ILIKE 不区分 |
| SQLite | % _ | 不支持 | 默认对 ASCII 不区分大小写 |
如果数据规模较大、业务又要求复杂的文本检索,不建议继续堆叠多个 LIKE 条件,而应评估全文索引、倒排索引或搜索引擎。例如 MySQL 的 FULLTEXT 索引、PostgreSQL 的 tsvector 和 GIN 索引,都能处理包含匹配和相关性排序。总结起来,通配符写法要遵循三条原则:确定字符尽量放前面、特殊字符显式 ESCAPE、参数化并转义用户输入。这样能兼顾查询灵活性与执行效率。