必须先调用 table() 再 query(),因 table() 初始化查询上下文,query() 是模型方法且 DB 门面无此公开方法;链式中混用 orWhere() 需闭包分组防优先级错误;select() 宜置于 where()/join() 后、orderBy()/paginate() 前;paginate() 前不可调用 toSql() 等消耗 Builder 的方法。

query() 和 table() 哪个该先调用
必须先 table(),再 query()。Laravel 的查询构造器设计里,table() 是入口,它初始化查询上下文(包括表名、连接、语法编译器),而 query() 是 Eloquent 模型上的静态方法,本质是返回一个已绑定表的新 Builder 实例。如果反着来,比如 DB::query()->table('users'),会直接报错:Call to undefined method Illuminate\Database\Query\Builder::table()。
-
DB::table('users')->where('id', 1)->get()✅ 正确起点 -
DB::query()->from('users')...❌query()不是 DB 门面的公开方法,不存在 - 想复用查询逻辑?封装成闭包或独立查询类,别依赖错误调用顺序
where() 链式中多个条件怎么写才不丢括号优先级
直接连写 where() 默认是 AND 连接,但一旦混入 orWhere(),括号就容易失控——SQL 生成时会把所有 orWhere() 提到最外层,导致本意是 “(A AND B) OR C” 却变成 “A AND B OR C”,结果错漏。
- 用闭包分组:
->where(function ($q) { $q->where('a', 1)->orWhere('b', 2); }),生成WHERE (a = 1 OR b = 2) - 避免连续写
where()->orWhere()->where(),这种写法语义模糊,不同 Laravel 版本解析行为可能不一致 - Laravel 9+ 支持
whereBelongsTo()等语义化方法,它们内部自动处理关联表 JOIN 和 WHERE 分组,比手写where()更安全
select() 放在链式中间还是末尾
select() 可以放中间,但位置影响后续方法可用性。比如 select('id') 后再调用 withCount('posts'),没问题;但若先 withCount() 再 select(),就可能丢掉计数字段(因为 select() 会覆盖默认的 *,而 withCount 添加的字段不在你显式列出的字段里)。
- 习惯上把
select()放在where()、join()之后,orderBy()、paginate()之前 - 需要动态字段?用
addSelect()替代重复select(),避免覆盖:比如select('name')->addSelect(DB::raw('COUNT(*) as total')) - 注意
distinct()和select()顺序:必须select()在前,否则distinct可能作用于隐式*,结果不可控
paginate() 为什么总查出空数组却没报错
常见原因是 paginate() 调用前漏了 from() 或 table(),或者中间用了不兼容的修饰方法(如 toSql()、dump())。paginate() 是终态方法,它会触发两次查询:一次算总数(SELECT COUNT(*)),一次取数据(SELECT ... LIMIT)。如果链式中途调用了 toSql(),查询就被“消费”掉了,后续 paginate() 拿不到原始 Builder,只能返回空集合。
- 检查是否误写了
->toSql()->paginate()—— 这是典型错误,toSql()返回字符串,不是 Builder - 使用
cursorPaginate()替代时,注意它不支持orderByRaw()和部分复杂排序,会抛InvalidArgumentException - 调试时用
dd($builder->toSql(), $builder->getBindings())看最终 SQL,别只看dd($builder->paginate())
clone 或重新构建。

















