fetchsql(true) 返回含占位符的sql字符串,须置于链式调用末尾且不可与select()/find()混用;错误调用会导致空结果或报错,真实sql需结合getlastsql()或开启show_sql调试。

fetchSql(true) 才能拿到 SQL 字符串,不传参数或传 false 就等于没调用——它不会中断执行,也不会返回 SQL,只会默默设个内部标记。
fetchSql(true) 必须放在链式调用末尾,且不能和 select()/find() 混用
常见错误是写成 $model->where('id=1')->fetchSql()->select(),结果 select() 返回 null 或空数组,控制台也没输出 SQL。这是因为 fetchSql()(无参数)只设置 options['fetchsql'] = true,但后续 select() 仍会尝试执行查询;而 fetchSql(true) 的返回值是字符串,不是 Query 对象,链式调用直接断掉。
- ✅ 正确写法:
$sql = $model->where('id', 1)->fetchSql(true)->find();——find()不执行,$sql是字符串 - ❌ 错误写法:
$model->fetchSql()->where(...)->select()——fetchSql()在开头,后面条件可能被忽略 - ❌ 错误写法:
$model->where(...)->fetchSql(true)->select()——fetchSql(true)已返回字符串,select()会报错“Call to a member function select() on string”
fetchSql() 输出的是预处理语句,含 ? 占位符,不是可直接运行的 SQL
比如 $model->where('status', 'normal')->where('score', '>', 80)->fetchSql(true)->select() 可能返回:SELECT * FROM think_user WHERE status = ? AND score > ?。这不是 bug,是 PDO 绑定机制决定的。你没法靠它验证字段拼写或表别名是否生效。
- 要看带真实参数的 SQL,得开调试:
'SHOW_SQL' => true,再查Db::getLog()或日志文件 - 临时想看完整 SQL?用
getLastSql():先真正执行一次查询(如->select()),再立刻调->getLastSql(),它返回的是最后那条已执行语句的完整文本 - 子查询场景下,
buildSql()更合适——它自动加括号,返回形如(SELECT id FROM think_user WHERE status = ?)的片段,专为嵌套设计
复杂 JOIN 或 alias 场景下,fetchSql() 容易误导人
当你写了 ->alias('a')->join('think_role r', 'a.role_id = r.id'),fetchSql(true) 输出的 SQL 可能混用 a.id 和 think_role.id,尤其在没显式指定字段前缀时,肉眼难判断字段到底从哪张表来。
- 分段调试更可靠:每加一个
join()或field(),就接一次fetchSql(true)单独跑,确认别名和关联条件是否按预期生成 -
view()定义的视图,fetchSql()只输出 SELECT 部分,不包含CREATE VIEW,别指望它帮你验视图语法 - 用了
union()或with(),fetchSql()可能漏掉部分子句或顺序错乱,这时优先看getLastSql()的实际执行结果
真正麻烦的从来不是怎么打出 SQL,而是打出的 SQL 和你脑中想的是否一致——占位符、别名作用域、JOIN 顺序、字段歧义,这些细节在 fetchSql() 的字符串里全被压缩成一行,得靠分段 + getLastSql() + 实际执行三者交叉验证才稳得住。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











