【问题标题】:MySQL & PHP : Multiple Keyword SearchMySQL & PHP : 多关键字搜索
【发布时间】:2013-04-08 16:48:00
【问题描述】:

我有一个包含逗号分隔关键字的字符串。例如:

$keywords = 'keyword1, keyword2, keyword3';

我的表架构,名为tbl_address 是这样的(简化):

id        INT(11)        PRIMARY KEY, AUTO INCREMENT
address   VARCHAR(250)   NOT NULL

假设我必须在 PHP 中使用 MySQLi(而不是 PDO)。

这是我目前的做法:

$result = array();
$keyword_tokens = explode(',', $keywords);
foreach($keyword_tokens as $keyword) {
  $keyword = mysqli_real_escape_string(trim($keyword));
  $sql = "SELECT * FROM tbl_address WHERE address LIKE'%$keyword%'";
  // query and collect the result to $result
  // before inserting to $result, check if the id exists in $result.
  // if yes, skip.
}
return $result;

这种方法有效,但性能低下。如果有很多关键字,它将进行很多查询。

我的问题是,有没有更好的方法来实现相同的目标?即返回地址包含任何关键字的所有记录的最简单方法是什么?

【问题讨论】:

标签: php mysql


【解决方案1】:

最好的方法是使用全文搜索。

http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html

如果您不想使用全文,可以在 WHERE 条件中使用 OR

SELECT * FROM tbl_address WHERE address LIKE '%$keyword%' OR adress LIKE '%$keyword2%'

【讨论】:

  • 如果您有多个关键字,您可以创建一个字符串,例如 ::-> SELECT * FROM tbl_address WHERE address LIKE "%key1%key2%key3%"
【解决方案2】:
 SELECT * FROM user;
 +---------+----------+
 | user_id | username |
 +---------+----------+
 |     101 | Adam     |
 |     102 | Ben      |
 |     103 | Charlie  |
 |     104 | Dave     |
 +---------+----------+

 SELECT * 
   FROM user 
  WHERE FIND_IN_SET(username,'adam,ben,dave') > 0;
 +---------+----------+
 | user_id | username |
 +---------+----------+
 |     101 | Adam     |
 |     102 | Ben      |
 |     104 | Dave     |
 +---------+----------+

【讨论】:

  • 这种方法有两个注意事项。不能使用 LIKE 语法并且不修剪关键字...
【解决方案3】:

最好的方法是创建搜索字符串 WHERE 子句并将其附加到查询并运行一次。

$result = array();
$keyword_tokens = explode(',', $keywords);
$where = '';$i=0
foreach($keyword_tokens as $keyword) {
  $where.= " address LIKE'%".mysqli_real_escape_string(trim($keyword))."%' OR ";
}
  // trim last OR with substr_replace
  substr_replace($where, "OR", -1, 1);
  $sql = "SELECT * FROM tbl_address WHERE $where";

return $result;

【讨论】:

    【解决方案4】:

    你好用联合创建一个查询并在循环结束时执行

    $result = array();
    $keyword_tokens = explode(',', $keywords);
    $sql = '';
    foreach($keyword_tokens as $keyword) {
      $keyword = mysqli_real_escape_string(trim($keyword));
      if (!empty($sql)) $sql .= " UNION "; 
      $sql .= "SELECT * FROM tbl_address WHERE address LIKE'%$keyword%'";
      // query and collect the result to $result
      // before inserting to $result, check if the id exists in $result.
      // if yes, skip.
    }
    

    在此处执行查询。

    【讨论】:

      【解决方案5】:

      您只需要一个“或”,没有其他...

      <?php
      
      $result = array();
      $keyword_tokens = explode(',', $keywords);
      $keyword_tokens = array_map('mysqli_real_escape_string', $keyword_tokens);
      
      $sql = "SELECT * FROM tbl_address WHERE address LIKE'%";
      $sql .= implode("%' or address LIKE '%", $keyword_tokens) . "'";
      
      // query and collect the result to $result
      // before inserting to $result, check if the id exists in $result.
      // if yes, skip.
      
      return $result;
      

      编辑:只是为了确保您还修剪了关键字

      <?php
      
      $result = array();
      $keyword_tokens = explode(',', $keywords);
      $keyword_tokens = array_map(
          function($keyword) {
              return mysqli_real_escape_string(trim($keyword));
          }, 
          $keyword_tokens
      );
      
      $sql = "SELECT * FROM tbl_address WHERE address LIKE'%";
      $sql .= implode("%' OR address LIKE '%", $keyword_tokens) . "'";
      
      // query and collect the result to $result
      // before inserting to $result, check if the id exists in $result.
      // if yes, skip.
      
      return $result;
      

      此外,您还应该将 db 资源链接传递给 mysqli_real_escape_string() 函数...

      【讨论】:

      • 你错过了 $sql 的尾随单引号。
      【解决方案6】:

      进行单个查询

      $keywordary = explode(',', $keywords);
      foreach($keywordary as $keyword) {
        $keys = trim($keyword);
          $other .=" or address like '%$keys%'";
      }
      $sql = "SELECT * FROM tbl_address WHERE address LIKE'%$keyword%' $other";
      
      execute query;
      return $result;
      

      【讨论】:

      • 不应该是 $other .=" 而不是 $other =" 在你的循环中?否则,您将取消每个循环中的 or 子句。
      【解决方案7】:

      一个简单的REGEXP 可能就是您所追求的。您必须检查它对自己的效率。

      SELECT * FROM tbl_address WHERE field REGEXP 'keyword1|keyword2|keyword3';

      【讨论】:

      • +1,这正是我要找的,我还学习了一个新的MySQL字符串函数!
      • 很好的答案,这帮助我解决了一周的研究,并帮助我跳过了 30% 的问题 :)
      【解决方案8】:

      试试 WHERE IN 子句:

      $keyword = (array)explode(',', $keywords);
      for($i=0;$i=count($keyword);$i++){
         $keyword[$i]=mysqli_real_escape_string(trim($keyword[$i]),'\'" ');
      }
      //This is what I suggest.
      $query='SELECT * FROM tbl_address WHERE address IN ("'.implode('","',$keyword).'")';
      

      在 MySQL 5.1 上成功测试。

      【讨论】:

        猜你喜欢
        • 2018-12-16
        • 1970-01-01
        • 2011-09-28
        • 1970-01-01
        • 2019-02-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多