在Eloquent 5.1中不支持对`statement`绑定?

时间:2015-09-30 02:01:28

标签: laravel eloquent laravel-5.1

我是Laravel的新手,并尝试在Eloquent中进行字符串查询。我试图使用DB::statement,但我一直在查询字符串中收到有关占位符的错误。看来我要么没有正确的语法,要么绑定未实现或不支持?

我想使用statement的原因是因为我正在做INSERT... SELECT,我无法在Eloquent中找到任何文档。

这是我的代码:

$ php artisan tinker
Psy Shell v0.5.2 (PHP 5.6.13-0+deb8u1 — cli) by Justin Hileman
>>> echo \DB::statement('CREATE DATABASE :db', [':db'=>'test']);
Illuminate\Database\QueryException with message 'SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 1 (SQL: CREATE DATABASE :db)'
>>> \DB::statement('CREATE DATABASE ?', ['test']);
Illuminate\Database\QueryException with message 'SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 1 (SQL: CREATE DATABASE test)'

这些是PDO的两种语法形式(?:string)。根据{{​​3}},DB中的其他方法(例如selectinsert)支持此功能。

这些错误的相关部分是near '?' at line 1 (SQL: CREATE DATABASE :db)near '?' at line 1 (SQL: CREATE DATABASE test)。 MySQL认为查询字符串中有一个未绑定的?。我甚至没有在第一个查询中使用该语法。我的结论是bind()方法没有正确绑定我的占位符。

documentation询问语法,但没有接受答案。

修改一个答案说statement()不支持CREATE。我使用SELECT尝试了一些查询,并使用两个占位符得到了相同的结果:

>>> \DB::statement('SELECT 1 WHERE \'a\' = ?', array('a'));
Illuminate\Database\QueryException with message 'SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE 'a' = ?' at line 1 (SQL: SELECT 1 WHERE 'a' = a)'
>>> \DB::statement('SELECT 1 WHERE \'a\' = :letter', array(':letter'=>'a'));
Illuminate\Database\QueryException with message 'SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE 'a' = ?' at line 1 (SQL: SELECT 1 WHERE 'a' = :letter)'

3 个答案:

答案 0 :(得分:1)

实际上,您可以在create中使用dropDB::statement()查询,但不会以这种方式使用命名绑定

以下是一些会成功的查询。

dropcreate不接受绑定。

>>> \Db::statement('create database test')
=> true
>>> \Db::statement('drop database test')                                                                                                                                              
=> true

请勿在声明

中使用反斜杠和单引号
>>> \Db::statement('insert into users (id, name) values (?, ?)', ['1', 'John'])
=> true 

DB::statement()仅在成功时返回ture,因此如果您想查看select结果,则应使用DB::select()

>>> \Db::statement('select * from users')
=> true
>>> \Db::select('select * from users')                                                                                                                                                
=> [
     {#770
       +"id": 1,
       +"name": "John",
     },
   ]

删除第二个参数中的前导:

>>> \Db::statement('update users set name = :name where id = :id', ['id' => 1, 'name' => 'John'])
=> true

如果您使用DB::updateDB::delete

,您将获得影响行
>>> \Db::delete('delete from users where id = :id', ['id' => 1])
=> 1

答案 1 :(得分:1)

您收到的错误只与Laravels DB :: statement()函数间接相关。它们都在该方法中失败

return $me->getPdo()->prepare($query)->execute($bindings);

在文件vendor / laravel / framework / src / Illuminate / Database / Connection.php中

对失败负责的是对PDO::prepare()

的调用

Docuemenation说:

  

参数标记只能表示完整的数据文字。文字,关键字,标识符和任意查询部分都不能使用参数绑定。例如,您不能将多个值绑定到SQL语句的IN()子句中的单个参数。

另请参阅上面php.net文档中的用户贡献说明。另外,请查看Can PHP PDO Statements accept the table or column name as parameter?

PDO不支持您的创建示例。

由于语法无效,SELECT示例失败的原因很简单。

\DB::statement('SELECT 1 WHERE \'a\' = ?', array('a'))

您只是缺少FROM子句。这个例子在我的测试计算机上运行良好:

$ret = \DB::statement('SELECT 1 FROM `users` WHERE `username` = ?', ["gregor"]);

但是

$ret = \DB::statement('SELECT 1 WHERE `username` = ?', ["testname"]);

生成您收到的确切错误。

另请注意,\ DB :: statement不会返回任何资源。它只是通过返回true或false来表示查询已成功。

如果要使用INSERT ... SELECT,则可以在insert()语句中使用DB :: raw()。一些谷歌搜索将帮助您,找到适当的解决方案。可能作为起点:Raw Queries in LaravelHow to use raw queries in Laravel

答案 2 :(得分:1)

您要做的是通过绑定传递表名。

DB::statement('select * from ?',['users'])

根据this post,这是不可能的。

当然,如果您想要清理数据,可以使用如下的短代码数组:

$tables = ['users','test','another'];

,查询看起来像:

$code = 0;
DB::statement("select * from $tables[$code] where a=?",[2]);
DB::statement("create table $tables[$code]");