Laravel用GROUP_CONCAT嵌套sum报SQL 1111错误,求按月按联系人求和方案
错误原因
- 报错
SQLSTATE[HY000]: General error: 1111 Invalid use of group function是因为SQL不支持直接嵌套聚合函数,SUM()和GROUP_CONCAT()都是聚合函数,不能直接写为GROUP_CONCAT(sum(documents.grand_total))的形式。 - 现有查询逻辑缺少「先按月份+联系人两个维度分组,计算每个联系人对应月份的grand_total总和」的步骤,所以直接拼接只能拿到所有单条记录的grand_total值,无法得到每个联系人的汇总值。
修复后的代码
$Months = DB::table(function ($query) { // 内层子查询:先按月份+联系人分组,计算每个联系人单月的总和 $query->from('documents') ->join('contacts', 'documents.contact_id', '=', 'contacts.id') ->selectRaw( 'SUM(documents.grand_total) as contact_total, DATE_FORMAT(documents.due_date,"%M") as month, contacts.name as contact_name' ) ->where([ ['documents.company_id', '=', session('current_company')], ['documents.document_type', '=', 1], ['documents.status', '=', 2], ]) // 把月份条件包在闭包里,避免和前面的where条件逻辑冲突 ->where(function ($q) { $q->whereMonth('documents.created_at', '=', now()) ->orWhereMonth('documents.created_at', '=', now()->subMonths(1)) ->orWhereMonth('documents.created_at', '=', now()->subMonths(2)) ->orWhereMonth('documents.created_at', '=', now()->subMonths(3)) ->orWhereMonth('documents.created_at', '=', now()->subMonths(4)) ->orWhereMonth('documents.created_at', '>', now()) ->orWhereMonth('documents.created_at', '<', now()->subMonths(4)); }) ->groupByRaw('DATE_FORMAT(documents.due_date,"%M"), contacts.id, contacts.name') ->orderBy('documents.due_date'); }, 'temp') // 外层查询:按月份聚合,拼接所有联系人的总和和姓名 ->selectRaw( 'GROUP_CONCAT(contact_total SEPARATOR ",") as total, month, GROUP_CONCAT(DISTINCT contact_name SEPARATOR ",") as names' ) ->groupBy('month') ->get();
逻辑说明
- 内层子查询先对每个月每个联系人的所有grand_total做求和,得到每个联系人对应月份的单条汇总记录
- 外层查询基于子查询的结果,按月份分组后直接拼接汇总值,即可得到每个月所有联系人各自的grand_total求和后的值,不会再出现同一个联系人多笔明细重复拼接的问题
- 额外修复了原查询中
orWhere导致的逻辑漏洞:原写法会导致company_id/document_type/status三个必填筛选条件被后面的orWhere覆盖,不符合业务筛选要求。
内容的提问来源于stack exchange,提问作者Zeeshan Haider
相关产品推荐
相关产品推荐

