Laravel Join中OrWhere查询异常:交易状态过滤失效求助
问题描述
需要在数据列表中展示企业的买卖交易:
- 采购交易通过
invoice.company_id(买家企业ID)识别 - 销售交易通过
transaction.store_id(卖家店铺/企业ID)识别
表关联逻辑:
invoice与transaction通过invoice_id关联,invoice存储买家信息与支付详情,transaction存储卖家信息与交易状态(Processing、Shipped等)invoice.company_id和transaction.store_id均关联至company表
业务场景:企业既可能作为买家采购,也可能作为卖家销售,需要用同一个数据集展示所有关联交易,因此使用orWhere匹配两种身份。
当前编写的查询执行后不符合预期,比如筛选Shipped状态(对应transaction.status=2)时,Processing状态(status=1)的数据也会被返回。
问题原因
查询逻辑存在括号层级错误,导致状态筛选与企业ID匹配的逻辑被打乱。原代码生成的SQL逻辑等价于:
WHERE (status = X AND invoice.company_id = ?) OR transaction.store_id = ?
这会导致只要transaction.store_id匹配当前企业ID,无论交易状态是什么都会被查询出来,完全绕过了状态筛选条件。
修正后的查询代码
需要把企业身份的匹配逻辑(invoice.company_id或transaction.store_id)包裹在独立闭包中,确保状态筛选对所有符合身份的交易生效:
$transactions = DB::table('transaction') ->leftJoin('invoice', 'invoice.id', '=', 'transaction.invoice_id') ->leftJoin('company', 'company.id', '=', 'transaction.store_id') // 注意:需补充关联transaction_details表,否则select中的course_name会报错 ->leftJoin('transaction_details', 'transaction_details.transaction_id', '=', 'transaction.id') ->select( 'transaction.*', 'invoice.id as invoice_id', 'invoice.unique_code as unique_code', 'invoice.second_unique_code as second_unique_code', 'invoice.company_id as inv_company_id', 'invoice.status as status_payment', 'invoice.category_transaction as category_transaction', 'invoice.no_invoice as no_invoice', 'invoice.user_details as user_details', 'transaction_details.course_name as product_name', 'company.id as store_id', 'company.name as store_name', 'company.email as store_email', 'company.phone as store_phone', 'company.logo as store_logo' ) ->where(function ($q) { $tab = request('tab'); // 统一添加状态筛选条件 match ($tab) { 1 => $q->where('transaction.status', 0), // Waiting Approved 2 => $q->where('transaction.status', 1), // Being Processed default => $q->where('transaction.status', 2), // 默认Shipped等状态 }; // 将企业身份匹配逻辑包裹在子闭包,确保与状态条件为AND关系 $q->where(function ($subQ) { $subQ->where('invoice.company_id', auth()->user()->company_id) ->orWhere('transaction.store_id', auth()->user()->company_id); }); }) ->latest() ->paginate(20);
补充优化建议
- 修复关联缺失:原代码中直接引用
transaction_details.course_name但未关联该表,需补充leftJoin避免报错 - 定义状态常量:将
0/1/2这类状态值定义为常量(如const STATUS_WAITING = 0;),提升代码可读性与维护性 - 空值过滤:因使用
leftJoin,需注意invoice或company字段为空的情况,必要时添加whereNotNull过滤无效数据
内容的提问来源于stack exchange,提问作者Roni Surya
相关产品推荐
相关产品推荐

