在数据库开发过程中,我们经常会遇到需要先通过子查询筛选出一批基础数据,再对这些基础数据做模糊匹配的场景,这种需求就需要将SQL嵌套查询和LIKE模糊匹配结合动态生成的子查询集来实现。不同的数据库语法略有差异,但核心逻辑是相通的,下面以常用的MySQL数据库为例展开说明。

基础概念说明
首先需要明确几个核心概念:
- SQL嵌套查询:指在一个SQL查询的WHERE子句、FROM子句或者其他部分中,嵌入另一个完整的SELECT查询,内部的查询称为子查询,外部的称为主查询。
- LIKE模糊匹配:是SQL中用于字符串匹配的操作符,支持
%匹配任意多个字符,_匹配单个字符。 - 动态子查询集:指子查询的结果不是固定的,会根据外部传入的参数或者主查询的条件动态变化的结果集合。
基础实现示例
假设我们有一个用户表user_info,结构如下:
| 字段名 | 类型 | 说明 |
|---|---|---|
| user_id | int | 用户ID |
| user_name | varchar(50) | 用户名称 |
| dept_id | int | 所属部门ID |
还有一个部门表dept_info,结构如下:
| 字段名 | 类型 | 说明 |
|---|---|---|
| dept_id | int | 部门ID |
| dept_name | varchar(50) | 部门名称 |
现在需求是:查询所有部门名称包含“技术”的部门下的用户,且用户名称中包含“张”字。这个需求就需要先通过子查询动态获取部门名称包含“技术”的部门ID集合,再在主查询中匹配用户名称。
实现代码如下:
-- 先通过子查询获取部门名称包含技术的部门ID集合,再匹配用户名称
SELECT
u.user_id,
u.user_name,
u.dept_id
FROM
user_info u
WHERE
u.dept_id IN (
-- 动态子查询集:根据部门名称模糊匹配得到部门ID
SELECT
d.dept_id
FROM
dept_info d
WHERE
d.dept_name LIKE "%技术%"
)
AND u.user_name LIKE "%张%";
动态参数场景的实现
如果子查询的条件不是固定的,而是需要外部传入参数动态生成,比如需要根据传入的部门名称关键词动态筛选部门,再匹配用户名称,可以通过预处理语句实现,示例代码如下:
-- 定义变量存储传入的部门名称关键词
SET @dept_keyword = "技术";
SET @user_keyword = "张";
-- 执行查询
SELECT
u.user_id,
u.user_name,
u.dept_id
FROM
user_info u
WHERE
u.dept_id IN (
SELECT
d.dept_id
FROM
dept_info d
WHERE
d.dept_name LIKE CONCAT("%", @dept_keyword, "%")
)
AND u.user_name LIKE CONCAT("%", @user_keyword, "%");
这里使用CONCAT函数拼接模糊匹配的字符串,避免直接拼接SQL导致注入风险,同时实现动态参数传入。
性能优化建议
这种嵌套查询加模糊匹配的方式如果数据量较大,可能会出现性能问题,可参考以下优化思路:
- 给
dept_info表的dept_name字段和user_info表的user_name字段添加普通索引,提升LIKE匹配的效率,注意如果LIKE以%开头,索引可能失效,尽量让模糊匹配的条件更明确。 - 如果子查询的结果集较小,可以将子查询改为关联查询,减少嵌套层级,示例代码如下:
-- 关联查询实现相同需求
SELECT
u.user_id,
u.user_name,
u.dept_id
FROM
user_info u
INNER JOIN
dept_info d ON u.dept_id = d.dept_id
WHERE
d.dept_name LIKE "%技术%"
AND u.user_name LIKE "%张%";
关联查询的执行计划通常比嵌套查询更优,在数据量大的场景下可以优先考虑。
注意事项
在使用这种查询方式时,需要注意几个问题:
- 子查询返回的字段必须和主查询中匹配字段的类型一致,否则会出现类型转换导致索引失效。
- 如果子查询可能返回NULL值,需要提前处理,避免主查询的IN条件出现NULL导致结果不符合预期。
- 动态拼接LIKE条件时,不要直接拼接用户输入的内容,防止SQL注入,尽量使用参数化查询或者预处理语句。