简体   繁体   English

获取由Laravel Eloquent中父模型中的字段筛选的相关列的SUM

[英]Get SUM of a related column filtered by a field in the parent model in Laravel Eloquent

I have the following tables: 我有以下表格:

purchase_orders 订单

  • id ID
  • status 状态

line_items line_items

  • id ID
  • purchase_order_id purchase_order_id
  • product_id PRODUCT_ID
  • qty 数量

products 制品

  • id ID
  • product_name 产品名称

A purchase order contains multiple line items and each line item has one product and a field for quantity (' qty '). 采购订单包含多个订单项 ,每个订单项都有一个产品和一个数量字段(' qty ')。

See ERD Model 请参阅ERD模型

Here is how I defined the Laravel models: 以下是我定义Laravel模型的方法:

Product Model: 产品型号:

class Product extends Model
{
    public function lineitems()
    {
        return $this->hasMany('App\LineItem');
    }
}

LineItem Model: LineItem模型:

class LineItem extends Model
{
    public function purchase_order()
    {
        return $this->belongsTo('App\PurchaseOrder', 'purchase_order_id');
    }

    public function product()
    {
        return $this->hasOne('App\Product', 'product_id');
    }
}

PurchaseOrder Model: PurchaseOrder型号:

class PurchaseOrder extends Model
{
    public function lineitems()
    {
        return $this->hasMany('App\LineItem');
    }

}

I would like to get the the SUM of all 'line_items.qty' for a 'product.id' filtered by the 'purchase_order.status' . 我希望得到所有'line_items.qty'的SUM,其中'product.id''purchase_order.status'过滤。

How do I go about writing the query in a Model function so that I can use it to loop through all products thru Blade @foreach ? 如何在Model函数中编写查询,以便我可以使用它通过Blade @foreach遍历所有产品?

Thank you in advance! 先感谢您!

If you want to get more speed and get everything all at once, then you can try this query : 如果您希望获得更高的速度并一次性获取所有内容,那么您可以尝试以下查询:

$products = Product::selectRaw('products.*, sum(line_items.qty) as qty_sum')
            ->join('line_items', 'line_items.product_id', '=', 'products.id')
            ->join('purchase_orders', 'purchase_orders.id', '=', 'line_items.purchase_order_id')
            ->where('purchase_orders.status', 'sold')
            ->groupBy('products.id')
            ->get();

But Your Database if MySql must accept whole grouping with one column that always matches with other columns. 但是你的数据库,如果MySql必须接受整个分组,其中一列总是与其他列匹配。

But if you want to stick to the Laravel relations only then, take the following steps. 但是,如果您只想坚持Laravel关系,请执行以下步骤。

1- When your table name is plural, PK is id , and FK is table name singular with _id ex (table products(id), table line_items(product_id)), there is no need to specify Foreign key in the Relations. 1-当你的表名是复数时,PK是id ,而FK是表名单数,带有_id ex(table products(id),table line_items(product_id)),不需要在Relations中指定外键。

2- Since it's a Many-to-Many case, you don't necessarily have to Define a Model for the Intermediate table line_items , you can have it for special and fast queries, but you can handle CRUD on it via Laravel Pivot system. 2-由于它是多对多的情况,您不一定要为中间表line_items定义模型,您可以将它用于特殊和快速查询,但您可以通过Laravel Pivot系统处理它上面的CRUD。 You can learn more about Pivot https://laravel.com/docs/5.7/eloquent-relationships#many-to-many 您可以了解有关Pivot的更多信息https://laravel.com/docs/5.7/eloquent-relationships#many-to-many

Retrieving Intermediate Table Columns 检索中间表列

As you have already learned, working with many-to-many relations requires the presence of an intermediate table. 正如您已经了解的那样,处理多对多关系需要存在中间表。 Eloquent provides some very helpful ways of interacting with this table. Eloquent提供了一些与此表交互的非常有用的方法。 For example, let's assume our User object has many Role objects that it is related to. 例如,假设我们的User对象有许多与之相关的Role对象。 After accessing this relationship, we may access the intermediate table using the pivot attribute on the models: 访问此关系后,我们可以使用模型上的pivot属性访问中间表:

So your Models could look like this : 所以你的模型看起来像这样:

Product Model: 产品型号:

class Product extends Model
{
    public function purchaseOrders()
    {
        return $this->belongsToMany('App\PurchaseOrder', 'line_items')->withPivot('qty')->withTimestamps();
    }

    public function soldPurchaseOrders()
    {
        return $this->belongsToMany('App\PurchaseOrder', 'line_items')
                    ->where('status', 'sold')
                    ->withPivot('qty')->withTimestamps();
    }
}

PurchaseOrder Model: PurchaseOrder型号:

class PurchaseOrder extends Model
{
    public function products()
    {
        return $this->belongsToMany('App\Product', 'line_items')->withPivot('qty')->withTimestamps();
    }

}

Use ->withPivot('field1', 'field2', 'etc') , and ->withTimestamps() if your pivot table has created_at , updated_at columns. 如果您的数据透视表有created_atupdated_at列,请使用->withPivot('field1', 'field2', 'etc')->withTimestamps() And access pivot value with prefix pivot_ +attribute in query builder, and with pivot-> +attribute in results object method, ex : $products->first()->pivot->qty . 并在查询构建器中使用前缀pivot_ +属性访问数据透视值,并在结果对象方法中使用pivot-> +属性,例如: $products->first()->pivot->qty

If you still want to use LineItem model, then change Product relation to belongsTo . 如果您仍想使用LineItem模型, belongsTo Product relation更改为belongsTo

LineItem Model: LineItem模型:

class LineItem extends Model
{
    public function purchaseOrder()
    {
        return $this->belongsTo('App\PurchaseOrder');
    }

    public function product()
    {
        return $this->belongsTo('App\Product');
    }
}

3- And finally to retrieve Products with SUM of qty use the following codes : 3-最后用qty的SUM检索产品使用以下代码:

Use eager loading to autoload Purchase Orders for all Products all at once in 1 request to avoid N-Products + 1 requests to Database. 在1个请求中使用预先加载来自动加载所有产品的采购订单,以避免N-Products + 1个数据库请求。 https://laravel.com/docs/5.7/eloquent-relationships#eager-loading https://laravel.com/docs/5.7/eloquent-relationships#eager-loading

$products = Product::with('soldPurchaseOrders')->get();

foreach($products as $product) {
    $qtySum = $product->soldPurchaseOrders->sum('pivot.qty');
    echo '<br/> Product '.$product->id.' - '.$product->name.' - '.$qtySum;
}

So at the end, Laravel will convert this with INNER JOIN query like the 1st example above, but only with fancy design and Pivot table. 所以最后,Laravel将使用INNER JOIN查询转换它,如上面的第一个例子,但只有花哨的设计和数据透视表。

EDIT------ 编辑 - - -

After OP specify orders status as sold , I've update the codes to use sold. OP指定订单状态为sold ,我已更新要使用已销售的代码。

EDIT 2 ----- 编辑2 -----

Replace $product->pivot->qty by $qtySum . $qtySum替换$product->pivot->qty $qtySum $product->pivot->qty Pivot quantity will be available after calling the soldPurchaseOrders relations like : 在调用soldPurchaseOrders关系之后,将提供枢轴数量,例如:

foreach($product->soldPurchaseOrders as $order) {
    echo '<br/>Order .'$order->id.' - '.$order->pivot->qty;
} 

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

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