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

Laravel Eloquent使用WHERE CONCAT查询结果与MariaDB不一致

问题诱因说明

该问题和查询条件中的斜杠/完全无关,核心诱因是**orWhereRaw方法的参数绑定写法错误**,同时存在几个潜在隐患会放大查询结果不一致的问题。


核心错误点:参数绑定写法不符合PDO预处理规则

你写的原始代码中,orWhereRaw部分如下:

->orWhereRaw("(CONCAT(`contract_no`, `po_additional_no`) LIKE '%?%')", [$request->q])

Laravel底层使用PDO预处理语句执行SQL,占位符?的使用有严格规则:

  • 占位符不能被包裹在SQL语句的引号字符串内部,否则PDO不会将其识别为需要替换的参数标记,会直接把?当成普通字符串处理。
  • 通配符%需要拼接在绑定参数的外部传入,不能直接写在SQL语句里包裹占位符。

这种错误写法会导致两个直接结果:

  1. 实际发送给数据库执行的SQL中,该条件会变成CONCAT(...) LIKE '%?%',完全不会匹配你传入的搜索关键词
  2. 你传入的$request->q参数没有对应的占位符接收,会触发PDO参数数量不匹配的异常,如果你的项目全局异常处理做了兜底吞错(比如AJAX请求统一返回空结构),就会表现为查询返回空结果。

你看到的“生成的SQL语句”是框架通过替换占位符模拟出来的日志内容,不是数据库实际接收到执行的真实SQL,所以你手动把参数拼进去在客户端执行能得到结果,但框架实际执行时逻辑完全错误。


其他潜在隐患

除了核心的参数绑定错误,你的代码还有三个容易导致结果不一致的问题:

  • 字段歧义风险:CONCAT中使用的contract_no、po_additional_no字段没有加表前缀,多表join时如果其他表存在同名字段,会触发SQL错误或者匹配到错误的字段值。
  • OR条件逻辑风险:你直接链式调用where+多个orWhere,虽然当前因为软删除全局作用域自动给OR条件加了括号,但如果后续新增其他查询条件,很容易出现OR条件优先级错误,导致查询范围超出预期。
  • 重复结果风险:你关联了commodity_po表但没有加去重逻辑,如果一个采购合同对应多条commodity_po记录,会返回重复的发票数据。

修复后的代码示例

$searchKeyword = '%' . $request->q . '%';
$invoice = PurchaseInvoice::select("purchase_invoices.*", "purchase_contracts.contract_no", "partners.name as partner_name")
    ->join("purchase_contracts","purchase_contracts.id","purchase_invoices.purchase_contract_id")
    ->join("partners","partners.id","purchase_contracts.partner_id")
    ->join("commodity_po","purchase_contracts.id","commodity_po.purchase_contract_id")
    // 手动把所有OR搜索条件包在闭包里,明确逻辑优先级
    ->where(function($query) use ($searchKeyword) {
        $query->where("purchase_invoices.invoice_no", 'LIKE', $searchKeyword)
            ->orWhere("purchase_invoices.po_additional_no", 'LIKE', $searchKeyword)
            ->orWhere("purchase_contracts.contract_no", 'LIKE', $searchKeyword)
            // 给字段加表前缀,通配符放在参数里绑定
            ->orWhereRaw("CONCAT(purchase_contracts.contract_no, purchase_invoices.po_additional_no) LIKE ?", [$searchKeyword]);
    })
    // 加去重避免join导致的重复结果
    ->distinct()
    ->get();

内容的提问来源于stack exchange,提问作者Miky Setiawan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 10:24:22