Php Laravel DB::语句无法为涉及列表达式的查询正确准备值
我想知道DB::statement和DB::unprepared查询之间出现的问题,因此显然DB::statement方法无法处理对列本身执行表达式的查询,类似这样的情况: 更新标记集?=?+2在哪里?>?用户_id=?和tree_id= 这将导致SQL为: 更新标记集rgt=rgt+2,其中rgt>2,用户id=1,树id=1 ^当在mysql解释器中使用此查询时,它工作得非常好,但使用laravel的DB::statement方法(使用未准备好的方法btw时,它工作得很好)会让它变得糟糕 这种不匹配背后的原因是什么 它弹出的错误是Php Laravel DB::语句无法为涉及列表达式的查询正确准备值,php,mysql,laravel,laravel-5,eloquent,Php,Mysql,Laravel,Laravel 5,Eloquent,我想知道DB::statement和DB::unprepared查询之间出现的问题,因此显然DB::statement方法无法处理对列本身执行表达式的查询,类似这样的情况: 更新标记集?=?+2在哪里?>?用户_id=?和tree_id= 这将导致SQL为: 更新标记集rgt=rgt+2,其中rgt>2,用户id=1,树id=1 ^当在mysql解释器中使用此查询时,它工作得非常好,但使用laravel的DB::statement方法(使用未准备好的方法btw时,它工作得很好)会让它变得糟糕 这
SQLSTATE[42000]:语法错误或访问冲突:1064您的SQL语法中有一个错误
,这很奇怪,因为它的语法正确,并且已经可以与mysql一起正常工作
所以语句方法就是这样做的:
{
return $this->run($query, $bindings, function ($query, $bindings) {
if ($this->pretending()) {
return true;
}
$statement = $this->getPdo()->prepare($query);
$this->bindValues($statement, $this->prepareBindings($bindings));
$this->recordsHaveBeenModified();
return $statement->execute();
});
}
而毫无准备的人:
{
return $this->run($query, [], function ($query) {
if ($this->pretending()) {
return true;
}
$this->recordsHaveBeenModified(
$change = ($this->getPdo()->exec($query) === false ? false : true)
);
return $change;
});
}
我认为问题在于prepare
方法
在其他地方发布的参考资料也无法确定问题:
用户建议高级查询应使用未准备好的方法?此查询尽可能基本:
另一位用户建议使用unprepared,而不是分解为更简单的查询:
奖金问题:
此外,如果你知道任何有说服力的方法来处理这个问题,那就太棒了!(从某种意义上讲,如何通过本机、where、update等方法处理列级表达式。)
编辑:
这个问题不是重复的,因为它仍然涉及对列值进行硬编码<代码>数据库::原始('column*2')
我的问题纯粹是不做任何硬编码语句,让laravel做绑定
例如:此查询-
DB::update(DB::raw(
'UPDATE tags SET ? = ? ? ? WHERE ? >= ? AND user_id = ? AND tree_id = ?'),
[$flag, $flag, $operator, $integer, $flag, $controlIndex, $user_id, $tree_id]
);
产生如下错误:SQLSTATE[42000]:语法错误或访问冲突:1064您的SQL语法有错误;请查看与MySQL服务器版本对应的手册,以了解在“?=?”附近使用的正确语法?在哪里?用户_id=?第1行的tree_id=?(SQL:UPDATE tags SET rgt=rgt+2,其中rgt>=1,user_id=1,tree_id=1)
只需看看SQL查询:
更新标记集rgt=rgt+2,其中rgt>=1,user_id=1,tree_id=1
——这是完全合法的,如果放在mysql解释器中就可以使用 好的,经过进一步检查,我发现不能绑定表/列名,只能绑定查询中的值
更多参考:
要理解为什么绑定表(或列)名不起作用,您必须理解预处理语句中的占位符是如何工作的:它们不是简单地替换为(适当转义的)字符串,而是执行结果SQL。相反,被要求“准备”语句的DBMS会给出一个完整的查询计划,说明它将如何执行该查询,包括它将使用哪些表和索引,无论您如何填写占位符,这些表和索引都是相同的
看起来你也不能绑定数据库名称——所以这不是Laravel或PHP的缺陷,而是数据库的设计方式
从my_表中选择名称(其中id=:value)的计划将与替换:value的内容相同,但无法计划看似相似的从:表中选择名称(其中id=:value),因为DBMS不知道实际要从哪个表中选择
因此,应该做的是拥有一个列的白名单,并确保在执行查询之前根据该白名单进行过滤。向开发人员提供了防止任何SQL注入的任务。我本以为Laravel可能会实现基于列的绑定,但它可能有自己的优缺点
$filleble
存在DB::table('tags')->where([
['user_id', $user_id],
['tree_id', $tree_id],
[$flag, '>', $controlIndex]
])->update([
$flag => DB::raw($flag . $operator . $integer)
]);
Tags::where([
['user_id', $user_id],
['tree_id', $tree_id],
[$flag, '>', $controlIndex]])
->crement($flag, $integer, $operator);
其中,$flag
,$operator
和$integer
只是枚举
更新:
当有人向我推荐递增
和递减
方法时,我在一些聊天论坛上问了同样的问题,这完全符合问题的解决方案!因此,我的更新查询调用如下所示:
DB::table('tags')->where([
['user_id', $user_id],
['tree_id', $tree_id],
[$flag, '>', $controlIndex]
])->update([
$flag => DB::raw($flag . $operator . $integer)
]);
Tags::where([
['user_id', $user_id],
['tree_id', $tree_id],
[$flag, '>', $controlIndex]])
->crement($flag, $integer, $operator);
crement
只是一个附加到Tags
模型的局部作用域方法,用于指示调用是递增还是递减。可能重复的调用可以这样做@Sahil-我刚刚编辑了这个问题,请注意,您链接的方法仍然涉及到对列的表达式进行硬编码,特别是DB::raw('column*2')
,有关更多上下文,请参阅问题的末尾,我在此处添加了编辑部分以解决您的评论。