Laravel中怎么实现多表连接查询_Laravel Join用法示例【实例】

1次阅读

该用 join() 而不是 eloquent 关联时:需一次性从多表取字段且字段不全属主模型,或 where 条件涉及关联表字段;join() 适合扁平化结果与数据库层过滤,而 eloquent 关联适合按需加载。

Laravel中怎么实现多表连接查询_Laravel Join用法示例【实例】

什么时候该用 join() 而不是 Eloquent 关联?

当你需要从多个表中一次性取字段、且这些字段不都属于主模型(比如查订单 + 用户 + 商品名称),又不想发多条 sql 或手动拼数组时,join() 是更直接的选择。Eloquent 关联(如 belongsTo)适合「以主模型为中心、按需加载」的场景;而 join() 适合「结果集扁平化、带条件过滤关联表字段」的场景。

常见误用:用 with() 加载大量关联再 PHP 层筛选,导致 N+1 或内存浪费;其实 WHERE 条件落在关联表字段上时,join() + where() 才是数据库层过滤的正解。

join()leftJoin()rightJoin() 怎么选?

绝大多数情况只用前两个:join()(内连接)只返回两表都能匹配上的记录;leftJoin() 保留左表全部记录,右表无匹配则字段为 NULL —— 比如查所有用户及其最近一笔订单,即使没下单也要显示用户,就得用 leftJoin()

注意:laravelrightJoin() 很少用,SQL 底层不推荐右连接,等价逻辑总能用 leftJoin() 反转左右表实现。

  • join('orders', 'users.id', '=', 'orders.user_id') → 只有下过单的用户
  • leftJoin('orders', 'users.id', '=', 'orders.user_id') → 所有用户,订单字段可能为 null
  • 别名写法:leftJoin('orders as o', 'users.id', '=', 'o.user_id'),后续 select() 可用 o.name

如何在 join() 后正确 select 字段并避免列名冲突?

直接 select('*') 很危险:多表同名字段(如 idcreated_at)会互相覆盖,最终结果中只保留最后一个表的同名列。必须显式指定字段,或用别名隔离。

示例:查用户姓名、订单号、商品标题

$results = DB::table('users')     ->join('orders', 'users.id', '=', 'orders.user_id')     ->join('products', 'orders.product_id', '=', 'products.id')     ->select(         'users.name as user_name',         'orders.order_no',         'products.title as product_title'     )     ->where('products.status', 1)     ->get();

关键点:

  • 所有字段加表前缀或别名,杜绝歧义
  • where() 可跨表写,但必须明确指定表名/别名(如 'products.status'
  • 如果要用聚合函数(如 count()),记得加 groupBy('users.id'),否则结果不可预期

用 Eloquent Model 调用 join() 时要注意什么?

可以,但要小心:Eloquent 查询构造器默认会加 from 表名和主键 id,如果你 join() 后又调用 paginate()first(),它仍试图按 Model 的主键处理,容易出错或漏数据。

稳妥做法:

  • 纯查询场景,优先用 DB::table(),不绑定 Model
  • 非要基于 Model,就用 User::query()->join(...),并在 select() 中显式包含 users.*(或至少 users.id),否则 get() 返回的对象可能无法正确实例化
  • 避免在 join() 后调用 with() —— 这会额外触发关联查询,违背了 join 的初衷

真正复杂的多表聚合、分组统计,往往更适合写原生 SQL 或视图,而不是硬套 Eloquent 链式调用。

text=ZqhQzanResources