Laravel关联查询orWhere子句报错:未知列'dso_name'
问题根源
这个错误其实很好理解——你用with('dso')做预加载,但却想直接在主表的where条件里用关联表的dso_name字段,这根本行不通。
with('dso')是Laravel的预加载机制,它的逻辑是:先查customer表拿到符合主条件的记录,再根据这些记录的关联ID批量查dso表,是两次独立的查询。所以数据库在执行主查询的时候,根本不知道dso_name这个字段(它属于dso表,不是customer表),自然就报1054错误了。
至于创建和读取场景能正常工作,是因为那些场景是拿到customer模型之后,通过模型关联(比如$customer->dso->dso_name)去访问预加载回来的dso数据,这时候已经是在内存里处理了,和数据库查询阶段没关系。
解决方案
有两种常用的方式解决这个问题,你可以根据需求选:
方法1:用whereHas筛选关联模型
whereHas是专门用来针对关联模型添加查询条件的,它会自动生成子查询或JOIN来过滤主模型。修改后的代码如下:
public function search_customer(Request $request){ $search = $request->input('search_customer'); $this->validate(request(),[ 'search_customer'=>'required|min:2' ]); $customers = customer::with('dso') // 把主表的OR条件包裹在闭包里,保证逻辑正确 ->where(function($query) use ($search) { $query->where('customer_name', 'LIKE', '%'.$search.'%') ->orWhere('billing_street', 'LIKE', '%'.$search.'%') ->orWhere('billing_city', 'LIKE', '%'.$search.'%') ->orWhere('service_street', 'LIKE', '%'.$search.'%') ->orWhere('service_city', 'LIKE', '%'.$search.'%') ->orWhere('main_phone', 'LIKE', '%'.$search.'%') ->orWhere('email', 'LIKE', '%'.$search.'%') ->orWhere('cc_email', 'LIKE', '%'.$search.'%') ->orWhere('rNumber', 'LIKE', '%'.$search.'%') ->orWhere('registrant', 'LIKE', '%'.$search.'%') ->orWhere('RSO', 'LIKE', '%'.$search.'%') ->orWhere('service_state', 'LIKE', '%'.$search.'%') ->orWhere('billing_state', 'LIKE', '%'.$search.'%'); }) // 给关联表加查询条件 ->orWhereHas('dso', function($query) use ($search) { $query->where('dso_name', 'LIKE', '%'.$search.'%'); }) ->get(); return response()->json($customers); }
这里一定要把主表的OR条件用where(function($query) {...})包裹起来,不然orWhereHas会和前面每个条件都形成OR逻辑,很可能查出不符合预期的结果。
方法2:手动JOIN关联表
如果你需要直接在查询里访问关联表的多个字段,或者要做排序,可以用join手动关联两张表:
public function search_customer(Request $request){ $search = $request->input('search_customer'); $this->validate(request(),[ 'search_customer'=>'required|min:2' ]); $customers = customer::with('dso') // 替换成你实际的关联字段,比如customers的外键是dso_id,dsos表主键是id ->join('dsos', 'customers.dso_id', '=', 'dsos.id') ->where(function($query) use ($search) { $query->where('customer_name', 'LIKE', '%'.$search.'%') ->orWhere('billing_street', 'LIKE', '%'.$search.'%') // ... 其他主表条件 ->orWhere('billing_state', 'LIKE', '%'.$search.'%') // 必须指定表名前缀,避免字段冲突 ->orWhere('dsos.dso_name', 'LIKE', '%'.$search.'%'); }) // 只选customer表的字段,防止两张表有同名字段时出错 ->select('customers.*') // 如果是一对多关联,可能需要去重 ->distinct() ->get(); return response()->json($customers); }
这种方式要注意替换成你实际的关联字段和表名,别写错了。
额外提示
你现在用了一堆LIKE '%...%',如果数据量变大的话,查询性能会很差。建议考虑:
- 给常用查询的字段加全文索引
- 用Laravel的全文搜索功能(比如MySQL原生全文索引,或者对接Elasticsearch)
内容的提问来源于stack exchange,提问作者T.A.
相关产品推荐
相关产品推荐

