繁体   English   中英

如何使用 Laravel 查询生成器构建这样的查询?

[英]How can I build such a query using Laravel query builder?

有一张 MySQL “类别”的表格。

类别 model 具有如下所示的“hasMany”关系。

public function children(){
    return $this->hasMany(self::class, 'parent_id');
}

在类别编辑页面上,为了将父类别分配给当前类别(为此我需要填写其 parent_id 字段),我必须生成一个 Select 标记,该标记将包含类别表中的所有行,除了当前一个及其所有子类别。

category_id  | parent_id
------------------------
1            | NULL
2            | 1
3            | 2
4            | 3
5            | NULL
6            | 5

For example,
for category_id 1, should be selected lines with category_id [5, 6]
for category_id 2, should be selected lines with category_id [1, 5, 6]
for category_id 3, should be selected lines with category_id [1, 2, 5, 6]
for category_id 4, should be selected lines with category_id [1, 2, 3, 5, 6]
for category_id 5, should be selected lines with category_id [1, 2, 3, 4]
for category_id 6, should be selected lines with category_id [1, 2, 3, 4, 5]

如果一个category有parent_id是NULL,则表示它没有父category。

简短回答:您需要EXCEPT所有记录,但当前类别中的递归记录除外。

对于递归部分,您可以使用: https://github.com/staudenmeir/laravel-adjacency-list

查看它默认包含的descendantsAndSelf()关系。

接下来,您需要构建EXCEPT查询。 查询生成器不包括除 function 之外的,因此您需要自己构建一个。

例如,我的一个控制器中有这个:

我有一个名为Thread的 eloquent model ,它是一个用于保存消息线程的 model 。 人们对这些线程有不同的查看权限,所以我需要几个查询来过滤出他们可以看到和看不到的线程。

我使用元素查询构建器和一些 I UNION预构建这些单独的查询。 比有一个明确排除线程的查询。 然后我结合了 unioned 和$excludeExplicit查询:

$query = Thread::query() 
    ->fromRaw( 
        '(SELECT * FROM ((' . $unioned->toSql() . ') EXCEPT ' . $excludeExplicit->toSql() . ') AS threads) AS threads', 
        array_merge($unioned->getBindings(), $excludeExplicit->getBindings()) 
    );

(见https://stackoverflow.com/a/64231210/9258054

这个原始查询的技巧在于参数绑定的合并。 此外,此查询的结果是 Eloquent 模型。 请注意,在使用UNIONEXCEPT等查询时,您需要确保两者的SELECT语句返回相同的列。

在代码中挖掘了一下之后,我找到了一个更优雅的解决方案。 我正在使用“文章”model 中创建的“类别”关系从数据库中进行选择

public function categories(){
    return $this->morphToMany(Category::class, 'categoryable');
}

在这样做时,我只 select 那些没有父类别的项目。 但是由于“类别”关系,所有子项 go 到“Article”集合,并且项目树构建正确,我不必使用“Join”进行复杂的查询。

public function topMenu(){
    View::composer('layouts.header', function ($view){
        $view->with('categories', Category::whereNull('parent_id')->where('published', 1)->get());
    });
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM