如何用MySQL查询含多数组单元格的8万行数据表?
首先咱们先理清楚核心问题:你需要从prod_designs表中查询那些pd_year字段(逗号分隔的年份字符串)包含搜索条件中任意一个年份的记录,而搜索条件来自prod_desigs_search_test表的pds_year字段(同样是逗号分隔的字符串,可能为空)。
现有代码的关键问题
你之前的代码里有个致命错误:从数据库取出的$pd_year_ex是字符串类型,不是数组,所以is_array($pd_year_ex)这个判断永远不会成立,导致你只能处理单个年份的情况,完全无法匹配多个年份的场景。
另外,直接用LIKE '%年份字符串%'的方式不够准确——比如如果搜索条件是201,会误匹配到2017;而且如果目标表的pd_year是2017,2018,搜索条件是2017,2016,LIKE '%2017,2016%'也匹配不到,因为目标字段里没有这个完整的子串。
正确的实现方案
MySQL提供了专门处理逗号分隔字符串的函数FIND_IN_SET(str, strlist),它会返回str在strlist(逗号分隔的字符串)中的位置,不存在则返回0。用这个函数可以准确匹配单个年份是否存在于目标字段中。
1. 处理搜索条件
先从prod_desigs_search_test取出搜索条件,处理空值并分割成年份数组:
$get_search = mysqli_query($con, "SELECT * FROM prod_desigs_search_test WHERE s_id = '$s_id'"); $new_search = mysqli_fetch_array($get_search); $pd_year_ex = trim($new_search['pds_year']); // 去掉空格,处理你插入时的' '情况 $year_conditions = []; if (!empty($pd_year_ex)) { $years = explode(",", $pd_year_ex); // 遍历每个年份,生成FIND_IN_SET条件 foreach ($years as $year) { $year = trim($year); // 去掉年份前后可能的空格 if (!empty($year)) { // 过滤空的年份(比如字符串里有连续逗号的情况) $year_conditions[] = "FIND_IN_SET('$year', pd_year)"; } } }
2. 构建WHERE子句并执行查询
根据生成的条件数组,拼接成最终的查询语句:
$where_clause = ""; if (!empty($year_conditions)) { $where_clause = "WHERE " . implode(" OR ", $year_conditions); } // 执行查询 $search_sql = "SELECT * FROM prod_designs $where_clause"; $search = mysqli_query($con, $search_sql);
如果搜索条件是2017,2016,2015,最终生成的SQL会是:
SELECT * FROM prod_designs WHERE FIND_IN_SET('2017', pd_year) OR FIND_IN_SET('2016', pd_year) OR FIND_IN_SET('2015', pd_year)
这个查询会准确找出所有pd_year字段包含这三个年份中任意一个的记录。
3. 针对8万行数据的优化建议
- 解决SQL注入风险:你现在直接把变量拼进SQL的做法非常危险,建议改用预处理语句:
if (!empty($year_conditions)) { // 生成占位符字符串 $placeholder_str = implode(', ', array_fill(0, count($years), '?')); // 生成条件模板 $condition_template = implode(' OR ', array_fill(0, count($years), 'FIND_IN_SET(?, pd_year)')); $search_sql = "SELECT * FROM prod_designs WHERE $condition_template"; $stmt = mysqli_prepare($con, $search_sql); // 绑定参数,str_repeat('s', count($years))表示所有参数都是字符串类型 mysqli_stmt_bind_param($stmt, str_repeat('s', count($years)), ...$years); mysqli_stmt_execute($stmt); $search = mysqli_stmt_get_result($stmt); } - 提升查询性能:
FIND_IN_SET无法使用索引,8万行数据的话查询可能会变慢。如果长期有这类需求,建议重构表结构——把逗号分隔的年份拆分成单独的关联表(比如design_years,包含design_id和year字段),这样可以用索引快速查询,性能会提升很多。
空字段处理
如果pd_year_ex为空,$where_clause会是空字符串,查询会返回prod_designs表的所有记录;如果目标表的pd_year字段为空,FIND_IN_SET会返回0,不会被匹配到。如果你想匹配空字段,可以在条件里加上OR pd_year IS NULL OR pd_year = ''。
内容的提问来源于stack exchange,提问作者Andrew Ferguson

