MySQL WHERE - "ignore" 选项的通配符?

MySQL WHERE - wildcard to "ignore" option?

由于遗留设计问题,我正在尝试找到解决此问题的最有效方法。使用带有两个字段的 TABLE: pk int(10), year timestamp 其中"pk"是主键,也用于被查找的文档编号。

我从用户那里收到的数据可能是那个整数,也可能是整数前面的项目的组合。例如:

用户来自的文档编号:"FM" + Last two digits of the year + "-A" + pk. 因此,2015 年的一个示例表单,主键为 1025,将是 FM15-A1025.

使用 AJAX,用户可以搜索以下任何内容来查找此(和其他)表单:

F
FM
FM1
FM15
FM15-
FM15-A
FM15-A1
FM15-A10
FM15-A102
FM15-A1025

我的问题是,结合使用 MySQL 和 PHP,我如何才能 return 所有适用于此搜索的 PK 值?显然,"F" 和 "FM" 将 return 所有值,但年份部分 2015 将给出与 2020 不同的答案。

我不知道 MySQL 通配符或方法允许您在搜索中忽略部分列,并且有很多 PHP(使用很多 CPU/memory in the process) 这个简单的查找。目前,我的 PHP 完成了工作,但对于这样一个简单的任务来说却非常复杂:

$cleansearch = strtoupper(filter_var($_POST['search']['value'],FILTER_SANITIZE_STRING));

$searchid = $searchyear ="";
if ($cleansearch==="p" || $cleansearch==="pk"){
   $searchid = " pk LIKE '%' ";
} else if (strlen($cleansearch) === 3) {
   for($i = 0; $i<10;  $i++   ) {
        $test = "IR".$i;
        if($test===$cleansearch){
            $searchid= "pk LIKE '%' ";
            $searchyear= " AND LEFT(DATE_FORMAT(year,'%y'), 1) =$i ";
        }       
    }
} elseif ((strlen($cleansearch) === 4) || (
    ((strlen($cleansearch)=== 5 && "-"===substr($cleansearch,4,1)) ||
    (strlen($cleansearch)=== 6 && "-D"===substr($cleansearch,4,2))))){
    $cleansearch=substr($cleansearch,0,4);
    for($i = 10; $i<100;  $i++   ) {
        $test = "IR".$i;
        if($test===$cleansearch){
            $searchid= "pk LIKE '%' ";
            $searchyear= " AND DATE_FORMAT(year,'%y') =$i ";
        }
    }
} elseif (strlen($cleansearch) > 6 && "-D"===substr($cleansearch,4,2) ) {
    for($i = 10; $i<100;  $i++ ) {
        $test = "IR".$i;
        if($test===substr($cleansearch,0,4) ){   
            $searchyear= " AND DATE_FORMAT(year,'%y') =$i ";
        }
    }
    $searchid= " LPAD(pk,4,'0') LIKE '".substr($cleansearch,6)."%' ";
}
if(!empty($searchid)){
   $wheresearchterm = " OR (".$searchid . $searchyear.") ";
} else {
   $wheresearchterm = "";
}
$query = "SELECT pk, year FROM myTable WHERE 1 $wheresearchterm;";//The search query

有没有更好的方法?

我建议创建一个 SQL 视图,让您的生活更轻松。

CREATE VIEW DocumentIdView AS
SELECT CONCAT('FM', DATE_FORMAT(year,'%y'), '-A', pk) AS docId, pk FROM table

然后在你的PHP代码中,你可以做一个

SELECT b.* FROM DocumentIdView a LEFT JOIN table b ON a.pk = b.pk WHERE a.docId LIKE 'FM15-A1%'

显然,如果您不希望有一个 SQL 视图,您可以将这两个选择结合起来。

SELECT * FROM (SELECT CONCAT('FM', DATE_FORMAT(year,'%y'), '-A', pk) AS docId, pk FROM table) a LEFT JOIN table b ON a.pk = b.pk WHERE a.docId LIKE 'FM15-A1%'

如果效果不佳,我建议将文档 ID 作为一列存储在 table 中以便快速查找。或者,如果更新 table 不是一个选项,请按照@rlanvin 的建议为查询创建一个 materialized view

使用允许 % 通配符的 MySQL 字符串运算符 LIKE,您可以拆分字符串并优化搜索条件。

$sql_where = "";
$search = "FM15-A1025";

if (strlen($search) >= 3) {
    $y = int(substr($search, 2, 2));
    $sql_where .= "DATE_FORMAT(year,'%y') LIKE '$y%'";
}
if (strlen($search) >= 7) {
    $pk = int(substr($search, 6));
    $sql_where .= " AND CAST(pk as char) LIKE '$pk%'";
}

请注意,虽然 LIKE 的性能很差,但如果您不特别注意避免 SQL-注入

,那么将您的 SQL-字符串粘合在一起可能会很危险