Laravel MySQL LIKE通配符查询未返回预期匹配结果的问题排查
问题原因与解决方案
核心原因
你的查询逻辑是用LIKE "%{$q}%"匹配完整的关键词子串:当搜索“Open ter”时,数据库会查找字段中包含Open ter(空格+小写ter)的内容,但目标条目里是Open Terms(空格+大写Terms)——LIKE不会自动对关键词的中间部分做模糊匹配,它只会匹配你给定通配符范围内的完整子串。
虽然utf8mb4_general_ci排序规则支持大小写不敏感(比如ter能匹配Ter),但它不会让短字符串自动匹配更长的包含它的字符串(比如ter不会匹配Terms),这就是为什么搜“Open ter”找不到目标条目,但搜“Terms”可以的原因。
解决方案
根据你的实际需求,有两种常见处理方式:
1. 匹配所有关键词(适用于需要同时包含“Open”和“ter”的场景)
拆分关键词为独立子条件,要求字段同时包含所有关键词:
use Illuminate\Support\Facades\DB; $keywords = array_filter(explode(' ', trim($q))); // 过滤空字符串 $query = Listing::select("name", "slug"); foreach ($keywords as $keyword) { $query->where(function ($subquery) use ($keyword) { // 用参数绑定避免SQL注入 $subquery->where("name", "LIKE", DB::raw("CONCAT('%', ?, '%')"), [$keyword]) ->orWhere("introduction", "LIKE", DB::raw("CONCAT('%', ?, '%')"), [$keyword]); }); } $data = $query->get();
2. 模糊匹配关键词片段(适用于“Open ter”要匹配“Open Terms”的场景)
把关键词中的空格替换为通配符%,让中间可以匹配任意字符:
use Illuminate\Support\Facades\DB; $processedQuery = str_replace(' ', '%', trim($q)); $data = Listing::select("name", "slug") ->where("name", "LIKE", DB::raw("CONCAT('%', ?, '%')"), [$processedQuery]) ->orWhere("introduction", "LIKE", DB::raw("CONCAT('%', ?, '%')"), [$processedQuery]) ->get();
注意事项
不要直接将用户输入拼接到SQL语句中(比如原代码的%{$q}%),存在SQL注入风险,建议使用上面的参数绑定写法。
内容的提问来源于stack exchange,提问作者Benjamin Mwendwa Munyoki
相关产品推荐
相关产品推荐

