需要用子查询解决,但是这种查询性能比较差,如果经常用到这种查询建议添加两个字段保存统计金额数据到合同表
Contract::query()
->withCount(['orders' => function ($query) {
$query->select(DB::raw("sum(amount)"));
}])
->withCount(['receipts' => function ($query) {
$query->select(DB::raw("sum(amount)"));
}])
->havingRaw('CAST(orders_count AS DECIMAL(10, 3)) < CAST(receipts_count AS DECIMAL(10, 3))')
->get();
楼上大佬已经写的很清楚了,我这里再补充一下,最新版Laravel
提供了新方法的withSum()
(此方法是自 Laravel 8.12 新增):
$res = \App\Models\Contract::query()
->withSum('hasManyOrders', 'money')
->withSum('hasManyReceipts', 'money')
->havingRaw('has_many_receipts_sum_money < has_many_orders_sum_money')
->get();
dd($res);
测试结果:
分页什么的,正常加就行了。
再补充一下吧,如果你的Laravel
版本低,那再给你写个addSelect()
的方式:
$res = \App\Models\Contract::query()
->addSelect([
'receipts_money' => \App\Models\Receipt::whereColumn('receipts.contract_id', 'contracts.id')->selectRaw('SUM(money)'),
'orders_money' => \App\Models\Order::whereColumn('orders.contract_id', 'contracts.id')->selectRaw('SUM(money)'),
])
->havingRaw('receipts_money < orders_money')
->get()
->toArray();
@LiamHao 大神, 为了提高查询效率,我准备在合同表里面,增加一个收款总额(Total))字段。但是因为是新增的字段,之前的合同数据这个字段都是空的。需要把之前已有的收款记录计算一下总额,然后更新到Contract表的总额字段中(Total)中。
这个update该怎么写呢?
@牛铁柱 洗数据的 SQL ,将receipts
表中相同contract_id
的数据对money
字段求和,然后更新到contracts
表中:
UPDATE `contracts`
LEFT JOIN (
SELECT
SUM(`receipts`.`money`) AS `receipts_total`,
`receipts`.`contract_id`
FROM `receipts`
GROUP BY `receipts`.`contract_id`
) AS `tmp_receipts` ON `tmp_receipts`.`contract_id` = `contracts`.`id`
SET `contracts`.`total` = `tmp_receipts`.`receipts_total`
参考下吧,by a way: 200多声望都算「新手」?
更新冗余字段,如果完全没有数据库基础,其实也可以用笨办法, 就把所有订单选择出来,根据合同ID,循环累加后,再循环一次,更新进去。
有点基础就用 group by 合同ID ,sum 出来。再循环一次,更新进去。
这样又好理解,又好记忆。 左联更新加子查询,估计你会一脸懵逼。
你说你是新手,那提醒你一下,更新收款总额的时候,不要用PHP计算然后执行update
,要用 increment
,转换成SQL
就是
UPDATE TABLE SET total = total + 本次收款金额 WHERE xxx
防止并发导致收款额错误
需要用子查询解决,但是这种查询性能比较差,如果经常用到这种查询建议添加两个字段保存统计金额数据到合同表