You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 12:56:07