基于同一列上的多个条件的多对多关系进行搜索

时间:2016-12-22 13:02:49

标签: php mysql laravel eloquent laravel-5.3

我的 laravel 5.3 项目中有多对多关系。 有两个与此问题相关的模型。它们是作业标记。 模型作业可以包含许多标记,以及与许多作业相关的模型标记。 我使用关键字" belongsToMany "分配了多对多的关系。在两个模型类中。 该关系的数据库是: 表:工作

________________
 id |  title    |
____|___________|
  1 |  Developer|
____|___________|
  2 |  Designer |
____|___________|
  3 |  Tester   |
____|___________|
  4 |  manager  |
____|___________|

表:标签

_________________
 id |  tag_name |
____|___________|
  1 |  php      |
____|___________|
  2 |  html     |
____|___________|
  3 |  css      |
____|___________|

数据透视表 job_tag

_____________________
 job_id |  tag_id   |
________|___________|
  1     |   1       |
________|___________|
  1     |   2       |
________|___________|
  2     |   1       |
________|___________|
  3     |   1       |
________|___________|
  3     |   2       |
________|___________|
  4     |   2       |
________|___________|

用户可以传递多个标签名称以检索与用户传递的两个标签相关的作业。( AND 条件)

示例:当用户传递 tag_name " php"和" html"我想显示工作的详细信息[id:1 title:developer]和[id:2 title:designer]。

提示检索具有标记的作业记录" php"和" html"

注意:未定义用户传递的标签名称数量,即用户可以尽可能多地传递。

以下是我尝试的内容:

$jobs = Job::whereHas('tags', function ($query) use($params) {
                    foreach ($params['tags'] as $tag) {
                        $query->where('tag', $tag);
                    }
                });

上面的代码不会返回任何内容,但会生成以下sql:

select * from `jobs` where exists (select * from `tags` inner join `job_tag` on `tags`.`id` = `job_tag`.`tag_id` where `job_tag`.`job_id` = `jobs`.`id` and (`tag` = css) and (`tag` = javascript))

我试图根据这个没有效果的sql获得结果。

希望你们能够理解我的问题并帮助我找到解决方案。 提前谢谢。

2 个答案:

答案 0 :(得分:1)

一种选择是使用多个whereHas

$query = Job::query();

foreach ($params['tags'] as $tag) {
    $query->whereHas('tags', function ($q) use($tag) {
        $q->where('tag', $tag);
    });
}

$jobs = $query->get();

OR

假设您有一个标记为id的数组:

$tag_ids = [2, 4];

然后你可以尝试:

Job::whereHas('tags', function($q) use($tag_ids) {
        $q->whereIn('tag_id', $tag_ids)
          ->groupBy('job_id')
          ->havingRaw('COUNT(DISTINCT tag_id) = '.count($tag_ids));
    })->get();

答案 1 :(得分:0)

在您的foreach中,您需要将标记与OR而不是AND进行比较。

$jobs = Job::whereHas('tags', function ($query) use ($params) {
    $query->where(function ($query2) use ($params) {
        foreach ($params['tags'] as $tag) {
            $query->orWhere('tag', $tag);
        }
    })
});

我不确定是否需要第二级关闭,但如果您在事后最终添加任何其他WHERE条件,则会有所帮助。