【问题标题】:Laravel Query Builder, Where based on condition?Laravel 查询生成器,根据条件在哪里?
【发布时间】:2019-11-27 02:08:51
【问题描述】:

我有一个下拉列表来选择一个父级,它是对页面的自引用。我想限制该下拉列表的结果,这样它就不会允许我将页面嵌套超过一层。

如果我编辑“儿子”页面,并且“儿子”有一个“孙子”,那么我不应该被允许选择“爸爸”作为儿子的父母,因为它会创建一个巢很深的

在以下情况下,当我编辑 Son 记录时,我不应该选择 Dad 作为它的父母,因为儿子有孩子。

+----+-----------+----------+
| id | parent_id |  title   |
+----+-----------+----------+
|  1 | NULL      | Dad      |
|  2 | NULL      | Son      |
|  3 | 2         | Grandson |
+----+-----------+----------+

现在在这种情况下,我应该能够在编辑 Son 记录时选择 Dad 作为父母,因为 Son 没有任何孩子

+----+-----------+----------+
| id | parent_id |  title   |
+----+-----------+----------+
|  1 | NULL      | Dad      |
|  2 | NULL      | Son      |
|  3 | NULL      | Grandson |
+----+-----------+----------+

我正在努力解决这个问题,以及如何将这一切包装在查询构建器中。

到目前为止我所拥有的

如果 Son 有自己的 Child,则以下代码有效,我将无法选择 Dad,这很好。但如果没有孩子,它就会失败。

归结为:我的父选择还应该允许显示 parent_id 为空的页面,但前提是当前记录 (Son) 没有任何子记录。

Recap: 仅当它没有出现在任何 parent_id 中时才显示记录,因此没有子项,如果出现则不显示任何记录.. 如果没有,它应该显示 parent_id 所在的记录空值。这可以在一个查询中实现吗?

$query->where('id', '<>', $page->id);
$query->where('parent_id', '<>', $page->id);

【问题讨论】:

  • 那么,只有在记录没有子记录且没有父记录的情况下,您才想选择记录?
  • 只有当记录没有出现在任何 parent_id 中,所以没有孩子,如果有,但是没有记录将被显示.. 如果没有,它应该显示 parent_id 的记录为空。
  • 你的解释很混乱:D,你能解释一下吗
  • 嗯,我有一个下拉列表来选择一个父级,它是对页面的自引用。我想限制该下拉列表的结果,这样它就不允许我嵌套一个页面超过一层。如果我编辑“儿子”页面,并且“儿子”有一个“孙子”,那么我不应该被允许选择“爸爸”作为儿子的父母,因为它会创建一个很深的巢跨度>
  • 我已经添加了我的答案试试看

标签: php mysql laravel query-builder


【解决方案1】:

您需要自行连接表,因为 where 子句是基于每行的。

使用左连接加入表本身,其中 ID 与父 ID 匹配。然后只选择连接表的 ID 为空的行。

$pages = DB::table('pages AS p')
            ->leftJoin('pages AS p1', 'p.id', '=', 'p1.parent_id')
            ->where('p.id', '<>', $page->id)
            ->whereNull('p1.id')
            ->select('p.*')
            ->get();

【讨论】:

  • 当没有人填写parent_id时,不返回任何结果,而当没有父母和孩子时,应该可以选择所有实体
  • 糟糕,应该是LEFT JOIN。看看修改后的答案。
  • 嗯还是没有..当我编辑“孩子”时,我可以选择“爸爸”作为父母,虽然我的孩子是孙子的父母,所以我应该不能出于这个原因选择爸爸。感谢您的宝贵时间!
  • 这可能更简单,如果“儿子”是他自己的父母,那么应该没有查询结果,因为我们不能将“儿子”耦合到任何其他记录..跨度>
  • 所以您希望不包含作为(任何元素的)父元素的元素?这就是全部逻辑?
【解决方案2】:

嗯...我认为不可能将其分解为一行,因为您将不得不循环 parent_id 列检查当前 id 是否在 parent_id 列中:

但不用担心:不同的方法会更容易:两个单独的表,因此关系不同:

Pages model: has one parent
Parents model: belongs to a page

有了上面的关系,你可以很容易地使用 eloquent 通过检查没有给定关系的位置来获得没有父级的东西:

分解:

Pages model:

public function parents () {
    return $this->hasOne(Parent::class, 'page_id');
}

对父母模型:

 Parents model:

 protected $fillable = ['page_id'];

 public function pages () {
     return $this->belongsTo(Page::class, 'page_id');
 }

【讨论】:

    【解决方案3】:

    您可以在 Page 模型中创建父子关系。

    public function parent()
    {
        return $this->belongsTo('Page', 'parent_id');
    }
    
    public function children()
    {
        return $this->hasMany('Page', 'parent_id');
    }
    

    现在,您可以检查 Page 是否有子节点,然后像这样提取父 id 为 null 的记录:

    $pages = Page::where('parent_id', null)->doesntHave('children')->get();
    

    这将为您提供父 ID 为空且没有子代的记录。希望你能理解。

    【讨论】:

    • 恐怕我正在使用查询生成器,所以我无权访问 ->doesntHave()
    • @Notflip 嗯,创建一个模型将简化流程;)
    • 比这更复杂,我有一个模型,但我在 Nova 中使用这个方法,在一个名为 relatableQuery() 的函数中,填充是相关模型的下拉列表,我只能使用过滤查询生成器。
    • @Notflip 哦,我不熟悉新星兄弟。可能有办法
    • doesntHave - 太棒了!从来不知道这个函数的存在
    【解决方案4】:

    您可以使用带有 whereRaw 函数的查询构建器子查询来实现此目的 检查代码

    $result = DB::table('parents as p')
        ->whereRaw("parent_id is null and id not in (SELECT parent_id FROM parents WHERE parent_id is not null)")
        ->get();
    dd($result);
    

    o/p 看起来像这样
    第一种情况

    第二个场景

    它可以帮助你:)

    【讨论】:

    • 在我的第一个场景中,我不应该选择 Dad 案例,在您的示例中返回的是什么?
    • 这就是我正在寻找的答案。:-)
    • 好的很好:) 然后通过接受我的回答来结束你的问题。
    猜你喜欢
    • 2017-04-17
    • 2016-07-30
    • 2013-08-21
    • 2018-09-08
    • 2021-09-07
    • 1970-01-01
    • 2016-03-18
    • 2017-03-30
    • 1970-01-01
    相关资源
    最近更新 更多