Laravel 搜索查询 - SQL 'OR' 和 'AND' 的排序破坏了 foreach 循环查询
Laravel search query - SQL ordering of 'OR' and 'AND' ruining foreach loop query
我的搜索功能无法正常工作。目前,我有一个带有两个单选按钮('keywords' 和 'exact')的搜索表单,根据他们选择的内容,它应该在数据库中搜索给定的字符串数组或单个字符串(都是标题和描述一起应该包含所有搜索到的关键字)。当用户通过关键字(一堆单字串)进行搜索时,就会出现问题。目前,当我从表单中获取字符串时,我将其分解,然后 运行 一个 foreach 循环遍历它,但是,由于 SQL 对 'OR' 的排序,它最终搞砸了'AND' 运算符。
例如,search_value=black+darker 的搜索值会将 $query->toSql() 转换为
"select * from `animes` where `description` like ? or `name` like ? and `description` like ? or `name` like ?"
然而,SQL读作
"select * from `animes` where (`description` like ?) or (`name` like ? and `description` like ?) or (`name` like ?)"
这是我的代码(忽略与 'genre' 相关的任何内容,因为该部分按预期正常工作):
public function searchAnimes(SearchRequest $request)
{
if($request->search_type == 'keyword')
{
$animeSearchValues = explode(' ', Input::get('search_value'));
}
elseif($request->search_type == 'exact')
{
$animeSearchValues[0] = Input::get('search_value');
}
else
{
return redirect('animes');
}
$genres = $request->name;
$query = Anime::query();
if(isset($animeSearchValues) && strlen(Input::get('search_value')) >= 3)
{
foreach($animeSearchValues as $animeSearchValue)
{
$query->where('description', 'like', '%'.$animeSearchValue.'%')
->orWhere('name', 'like', '%'.$animeSearchValue.'%');
}
if(isset($genres))
{
foreach ($genres as $genre)
{
$query->whereHas('genres', function ($f) use ($genre)
{
$f->where('slug', $genre);
});
}
}
$animeResults = $query->orderBy('name')->paginate(10);
return view('animes.results', compact('animeResults'));
}
}
我能想到的唯一解决办法是把标题和描述都合并成一个字符串,然后在其中搜索每个单独的关键字,但是,这种方法似乎太过分了jerry-rigged 或非标准。另外,请记住,我需要在单个查询构建器中完成所有操作,这样我就可以分页显示结果。
谢谢。
我相信您需要使用 whereNested() 以便控制条件的分组。查看 Dayle Rees 的 page on Eloquent queries 了解详情
编辑:澄清一下,我想你会想要替换
foreach($animeSearchValues as $animeSearchValue)
{
$query->where('description', 'like', '%'.$animeSearchValue.'%')
->orWhere('name', 'like', '%'.$animeSearchValue.'%');
dump($query->get(), $animeSearchValue);
}
和
foreach($animeSearchValues as $animeSearchValue)
{
$query->whereNested( function($query) use($animeSearchValue)
{
$query->where('description', 'like', '%'.$animeSearchValue.'%')
->orWhere('name', 'like', '%'.$animeSearchValue.'%');
}
dump($query->get(), $animeSearchValue);
}
使用 whereNested 的好处是每个实例都在主查询中用 AND 连接在一起,因此每个单独的关键字都需要出现在描述或名称字段之一中。然后,您的示例将被解析为:
"select * from `animes` where (`description` like ? or `name` like ?) and (`description` like ? or `name` like ?)"
这是你想要的吗?这将搜索在标题或描述中包含每个关键字的所有内容。
foreach($animeSearchValues as $animeSearchValue){
$query->where(function ($q) use ($animeSearchValue){
$q->where('description', 'like', '%'.$animeSearchValue.'%')
->orWhere('name', 'like', '%'.$animeSearchValue.'%');
});
}
我的搜索功能无法正常工作。目前,我有一个带有两个单选按钮('keywords' 和 'exact')的搜索表单,根据他们选择的内容,它应该在数据库中搜索给定的字符串数组或单个字符串(都是标题和描述一起应该包含所有搜索到的关键字)。当用户通过关键字(一堆单字串)进行搜索时,就会出现问题。目前,当我从表单中获取字符串时,我将其分解,然后 运行 一个 foreach 循环遍历它,但是,由于 SQL 对 'OR' 的排序,它最终搞砸了'AND' 运算符。
例如,search_value=black+darker 的搜索值会将 $query->toSql() 转换为
"select * from `animes` where `description` like ? or `name` like ? and `description` like ? or `name` like ?"
然而,SQL读作
"select * from `animes` where (`description` like ?) or (`name` like ? and `description` like ?) or (`name` like ?)"
这是我的代码(忽略与 'genre' 相关的任何内容,因为该部分按预期正常工作):
public function searchAnimes(SearchRequest $request)
{
if($request->search_type == 'keyword')
{
$animeSearchValues = explode(' ', Input::get('search_value'));
}
elseif($request->search_type == 'exact')
{
$animeSearchValues[0] = Input::get('search_value');
}
else
{
return redirect('animes');
}
$genres = $request->name;
$query = Anime::query();
if(isset($animeSearchValues) && strlen(Input::get('search_value')) >= 3)
{
foreach($animeSearchValues as $animeSearchValue)
{
$query->where('description', 'like', '%'.$animeSearchValue.'%')
->orWhere('name', 'like', '%'.$animeSearchValue.'%');
}
if(isset($genres))
{
foreach ($genres as $genre)
{
$query->whereHas('genres', function ($f) use ($genre)
{
$f->where('slug', $genre);
});
}
}
$animeResults = $query->orderBy('name')->paginate(10);
return view('animes.results', compact('animeResults'));
}
}
我能想到的唯一解决办法是把标题和描述都合并成一个字符串,然后在其中搜索每个单独的关键字,但是,这种方法似乎太过分了jerry-rigged 或非标准。另外,请记住,我需要在单个查询构建器中完成所有操作,这样我就可以分页显示结果。
谢谢。
我相信您需要使用 whereNested() 以便控制条件的分组。查看 Dayle Rees 的 page on Eloquent queries 了解详情
编辑:澄清一下,我想你会想要替换
foreach($animeSearchValues as $animeSearchValue)
{
$query->where('description', 'like', '%'.$animeSearchValue.'%')
->orWhere('name', 'like', '%'.$animeSearchValue.'%');
dump($query->get(), $animeSearchValue);
}
和
foreach($animeSearchValues as $animeSearchValue)
{
$query->whereNested( function($query) use($animeSearchValue)
{
$query->where('description', 'like', '%'.$animeSearchValue.'%')
->orWhere('name', 'like', '%'.$animeSearchValue.'%');
}
dump($query->get(), $animeSearchValue);
}
使用 whereNested 的好处是每个实例都在主查询中用 AND 连接在一起,因此每个单独的关键字都需要出现在描述或名称字段之一中。然后,您的示例将被解析为:
"select * from `animes` where (`description` like ? or `name` like ?) and (`description` like ? or `name` like ?)"
这是你想要的吗?这将搜索在标题或描述中包含每个关键字的所有内容。
foreach($animeSearchValues as $animeSearchValue){
$query->where(function ($q) use ($animeSearchValue){
$q->where('description', 'like', '%'.$animeSearchValue.'%')
->orWhere('name', 'like', '%'.$animeSearchValue.'%');
});
}