如何获取 Laravel 删除/更新/插入语句的原始 SQL?

2022-08-30 23:30:31

我知道我可以在查询生成器上使用该方法来获取带有语句的绑定参数占位符的原始SQL。toSqlSELECT

App\User::where(['id'=>'1'])->toSql();
"select * from `users` where (`id` = ?)"

但是我怎么能得到这个声明呢?DELETE

App\User::where(['id'=>'1'])->delete()->toSql();

PHP 错误:调用第 1 行整数上的成员函数 toSql()

这将执行该语句,但我想获取生成的原始,未插值的SQL,其中的问号代表值,而无需实际运行查询。同样的情况也适用于任何修改声明,例如INSERTUPDATE

但为什么,谁在乎呢?

这闻起来很像一个xy问题。我的 Web 应用程序包括一个多进程体系结构。它运行自定义 artisan 命令,在更新数据库的事件驱动循环中侦听异步通信。

我需要原始查询的原因是,为了提高性能效率,我想重用预准备语句。不幸的是,雄辩的方法不会公开预准备语句,因此为了重用一个语句,我必须从基础 PDO 连接中自己准备它。

$sql = 'UPDATE `foo` SET `bar` = ? WHERE (`id` = ?)';

$statement = DB::connection()->getPdo()->prepare($sql);

while (true) {
    $data = foo();
    $statement->execute([$data->bar, $data->id]);
}

但是,这背离了抽象的 SQL 语法生成器。因为我现在正在使用MySQL,所以我可以在语法上包含反向引号。但现在我被困在供应商锁定中。例如,老板说我们明天要迁移到MS SQL Server,那么(至少)不得不捕获使用反引号而不是方括号的错误可能会很烦人。

我想使用动态生成的SQL语法在预准备语句中重用。


答案 1

首先获取模型表的查询生成器实例。

$builder = DB::table((new User)->getTable());

然后获取语法,并使用 where 子句从生成器编译 delete 语句。

$sql = $builder->getGrammar()->compileDelete($builder->where('id', 1));
"delete from `users` where `id` = ?"

现在,您可以自由交换数据库驱动程序,并且仍然可以获得适当的平台语法。


答案 2

你可以做这样的事情:

DB::enableQueryLog();
App\User::where(['id'=>'1'])->delete();
dd(DB::getQueryLog());

推荐