【问题标题】:Return rows based on multiple field search基于多字段搜索返回行
【发布时间】:2018-07-01 09:41:14
【问题描述】:

假设我有一个包含字段的表格:

name, email, designation, city

我想要的是用户可以通过在单个搜索框中输入单个词或多个词来搜索记录。例如。 ABC abc@gmail.com

现在我正在使用这样的东西:

$keywords = $request->get('search');
$searchValues = preg_split('/\s+/', $keywords, -1, PREG_SPLIT_NO_EMPTY);

$users = DB::table('users')
                    ->select('name', 'email',  'designation', 'city')
                    ->where(function ($query) use($searchValues){

                        foreach ($searchValues as $value)
                        {
                            $query->orWhere('name', 'like', "%{$value}%")
                                  ->orWhere('email', 'like', "%{$value}%")
                                  ->orWhere('designation', 'like', "%{$value}%")
                                  ->orWhere('city', 'like', "%{$value}%");
                        }
            })->latest('users.created_at')->paginate($perPage);

这可行,但有一个问题,它返回所有用户 name 'ABC',而不是只返回 name='ABC' 行> 和 email='abc@gmail.com'

我怎样才能做到这一点?

【问题讨论】:

  • 我对php不熟悉,但我觉得问题出在你使用orWhere?考虑一个条件表达式(name == 'abc' 或 email == 'bc@gmail.com'),当 name == 'abc' 为 True,则不会检查 email == 'bc@gmail.com ' 是 TrueFalse,所以结果是 name='ABC' 的所有行。把or改成and,你就会得到你想要的。
  • 我不知道 laravel 但似乎你应该使用 andWhere 代替 nameemail 而不是 orWhere 并隔离(带入括号)它们
  • 如果我删除 Or 然后它将检查每个关键字的所有列,并且由于 name='ABC' 不会出现在电子邮件或城市列中,它最终不会为我输入的任何关键字返回任何内容
  • 你不应该使用'ABC'来检查电子邮件,你必须找到哪个字符串是名称哪个字符串是电子邮件。
  • 这才是真正的问题。我只需要一个搜索框来允许搜索表的任何列,否则使用 WHERE AND 的解决方案非常简单

标签: php sql regex laravel-5


【解决方案1】:

MySQL 有一个鲜为人知的功能,称为MATCH (column1,column2) AGAINST ('keyword1 keyword2' IN BOOLEAN MODE),专为全文搜索而设计。它类似于类似 google 的搜索,其中关键字与列值匹配,其中最佳匹配是顶部结果。

请注意,您必须先清理搜索查询。某些符号在 MATCH AGAINST 中是禁止的。我编写了这个函数来清理它并准备搜索查询:

function returnMatchQuery($keyword)
{
    $keyword  = trim(str_replace(['+', '-', '~', '>', '<', '(', ')', '*', '´', '`'], ' ', $keyword));
    $keywords = collect(explode(' ', $keyword));
    $keywords = $keywords->map(function ($val)
    {
        return '+' . $val;
    });

    return implode(' ', $keywords->toArray());
}

在你的主要功能中:

$search_query = returnMatchQuery($keywords);
DB::table('users')->selectRaw("name,email,designation,city")
    ->whereRaw("MATCH (name,email,designation,city) AGAINST ('{$search_query}' IN BOOLEAN MODE)")
    ->->paginate($perPage);

注意-&gt;latest('users.created_at') 被释放。您可能需要也可能不需要添加它。结果可能有超过 1 条记录。第一个记录是最好的匹配。

更多信息请查看this MySQL page

【讨论】:

  • 它不是我问题的完整解决方案,但我仍然可以使用它。谢谢!
猜你喜欢
  • 1970-01-01
  • 2018-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-16
  • 2018-07-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多