Laravel Eloquent 模型按局部列和关系模型列值排序

Posted

技术标签:

【中文标题】Laravel Eloquent 模型按局部列和关系模型列值排序【英文标题】:Laravel Eloquent model order by local column and relation models column value 【发布时间】:2020-01-08 11:05:21 【问题描述】:

我有 2 个模型:

    产品,具有sort 字段。 Stock,具有 product_id 和数量字段。

我想获取按排序字段(ASC)排序的产品,但是库存数量等于0的产品需要在列表末尾。

例如

产品

id     sort
1      3
2      4
3      2
4      1

库存

product_id    quantity
1             2
1             3
2             5
3             0
4             2

预期列表(产品 ID) - 4、1、2、3

我已经编写了我需要做的 SQL 查询。

select p.url, p.sort, s.tot
from products p
inner join (select product_id, sum(quantity) as tot from stocks group by product_id) s on p.id = s.product_id
order by case when s.tot = 0 then 1 else 0 end, p.sort asc

这是 Product -> Stock的关系

public function stocks() 
    return $this->hasMany('\App\Stock', 'product_id');

有没有办法使用 Eloquent Model 的作用域来获得这种列表?

更新

解决办法。

public function scopeOrdered($query, $notInStock = false)
    
        if($notInStock)
            return $query->join(DB::raw("(
                select product_id, sum(quantity) as tot
                from stocks
                group by product_id
                ) s"), 'products.id', '=', 's.product_id')->orderByRaw("case when s.tot = 0 then 1 else 0 end, products.sort ASC");
        else
            return $query->orderBy('sort', 'asc');
    

【问题讨论】:

【参考方案1】:

您可以使用合并方法。但我认为您的数据库设计不正确。我认为最好将数量字段放在产品表上。 如果您出于任何原因想要保留此设计,最好在stocks 表中为product_id 设置唯一索引。例如,您的一个产品(id=1)现在有两个数量。这在现实世界中是不可能的

    $query1 = Product::whereHas('stocks' , function ($q) 
        $q->where('quantity', '<>',  0);
    )->with('stocks')->orderBy('sort','asc')->get();

    $query2 = Product::whereHas('stocks' , function ($q) 
        $q->where('quantity', 0);
    )->with('stocks')->get();


    $merged = $query1->merge($query2);

    return $merged;

您可以按照以下示例进行查询:

    $products = DB::table('products')
        ->join('stocks', 'stocks.product_id', '=', 'products.id')
        ->selectRaw(' product_id, sum(quantity) as tot')
        ->groupBy('product_id')
        ->orderByRaw(
            "CASE WHEN quantity = 0 THEN 1 ELSE 0 END ASC"
        )
        ->get();



    return $products;

【讨论】:

感谢您的帮助。我已经像你的第二个例子那样做了。问题是在库存表中,我将不同的存储与产品连接起来。这就像 manyToMany 关系。 很高兴您找到了答案。

以上是关于Laravel Eloquent 模型按局部列和关系模型列值排序的主要内容,如果未能解决你的问题,请参考以下文章

Laravel Eloquent在相关模型上按范围获取模型

Laravel Eloquent 按关系计数排序

按 id 分组 Laravel Eloquent 枢轴值

Laravel Eloquent按关系表列排序

Laravel Eloquent 按孩子的长度排序,然后分页

Laravel Eloquent 嵌套关系枢轴与约束