[英]Get SUM of a related column filtered by a field in the parent model in Laravel Eloquent
I have the following tables: 我有以下表格:
purchase_orders 订单
line_items line_items
products 制品
A purchase order contains multiple line items and each line item has one product and a field for quantity (' qty '). 采购订单包含多个订单项 ,每个订单项都有一个产品和一个数量字段(' qty ')。
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_at
, updated_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.