PDO 准备状态与手动查询的结果不同
Posted
技术标签:
【中文标题】PDO 准备状态与手动查询的结果不同【英文标题】:PDO prepared state not giving same result as manual query 【发布时间】:2015-02-24 11:27:36 【问题描述】:我正在使用 php 和 PDO 准备好的语句来访问数据库。我有这个准备好的查询,我想执行(通过一个 foreach 循环多次,但我看不出这真的会影响这个):
insert into forum_access (forum_id, user_id) select * from (select ?, ?)
as tmp where not exists (select * from forum_access
where forum_id = ? and user_id = ?) limit 1
然后我使用 PDO 执行与数组中的变量来执行此语句,如下所示:
$values = Array(2, 1, 2, 1); // Normally it's variables here
$stmt->execute($values);
这会执行,但奇怪的是它会在 forum_access 中插入一个值为 (2, 2) 的行。真正奇怪的是,当我使用手动插入的变量运行 SQL 查询时,如下所示:
insert into forum_access (forum_id, user_id) select * from (select 2, 1)
as tmp where not exists (select * from forum_access
where forum_id = 2 and user_id = 1) limit 1
它正确地插入了具有值 (2, 1) 的行。
我希望这与 PDO/mysql 处理预准备语句的方式有关。我或多或少是准备好的陈述的新手,不知道这里出了什么问题。希望其他人可以对此有所了解。
注意事项: 我有理由在重复键上使用相当复杂的插入...选择查询而不是插入...。也许不是完美的理由,但足以对从根本上改变查询的建议不感兴趣。
在 WAMP 服务器上使用 PHP 5.3 和 MySQL 5.0。
【问题讨论】:
你能导出准备好的语句本身吗? 你检查参数的顺序了吗?可能是有什么问题。命名参数会更好 【参考方案1】:我自己解决了这个问题。似乎 MySQL 对 select 语句中的插入值感到困惑,并将它们混合在一起。我试图命名这些值,如下所示:
insert into forum_access (forum_id, user_id) select * from
(select ? as forum_id, ? as user_id) as tmp
where not exists (select * from forum_access
where forum_id = ? and user_id = ?) limit 1
你瞧,这确实有效。
我仍然不确定它为什么会起作用。但我最关心的是获得一个可以工作的应用程序,所以目前我很满足。
感谢您的所有帮助,很抱歉打扰了我可以并且确实解决了自己的问题。
【讨论】:
【参考方案2】:$SQL = 'insert into forum_access (forum_id, user_id)
select *
from (select :forum_id1, :user_id1) as tmp
where not exists (
select *
from forum_access
where forum_id = :forum_id2 and user_id = :user_id2)
limit 1';
$forum_id1 = 2;
$user_id1 = 1;
$forum_id2 = 2;
$user_id2 = 1;
$stmt = $dbh->prepare($SQL);
$stmt->bindParam(':forum_id1', $forum_id1, PDO::PARAM_INT);
$stmt->bindParam(':user_id1', $user_id1, PDO::PARAM_INT);
$stmt->bindParam(':forum_id2', $forum_id2, PDO::PARAM_INT);
$stmt->bindParam(':user_id2', $user_id2, PDO::PARAM_INT);
$stmt->execute();
【讨论】:
您的建议是切换到命名占位符?您能否详细说明这将如何产生影响? 不幸的是,无论是这个解决方案还是 Peter Darmis 提出的解决方案似乎都不能解决问题。我还尝试将我的应用程序导出到 LAMP 服务器(PHP:5.4.4,MySQL:5.5.38),这导致错误 1060:列名重复“?”。我不确定如何正确解释这一点,但它似乎在某种程度上与 WAMP 服务器上奇怪的插入值有关。双 ?在插入中在某种程度上在准备好的语句解析中混乱,这在 LAMP 上给出了错误,在 WAMP 上给出了奇怪的插入值。不过还是不知道怎么解决。 请使用 'bindValue' 而不是 'bindParam' 因为您可以使用 'calculated' 值。仅对“blob”等“大型对象”使用“bindParam”。如果您使用 'bindParam',那么您必须传递一个包含所需值的 PHP 变量。自 PHP 5.3 以来,这种情况发生了变化吗? 这还能用吗? $stmt->bindParam(':forum_id1', 2, PDO::PARAM_INT) 什么时候运行?我希望它会引发错误,因为您没有将 PHP 变量传递给“绑定”。请告诉我它适用于哪个版本的 PHP。【参考方案3】:改变这个
$values = Array(2, 1, 2, 1); // Normally it's variables here
$stmt->execute($values);
有了这个
$values = Array(2, 1, 2, 1);
for($i=0;$i<count($values);$i++)
$stmt->bindParam(($i+1),$values[$i]);
$stmt->execute();
【讨论】:
这只会使代码更加冗长。我不明白为什么它会有所作为:-? 除非必须,否则不要使用'bindParam'。除非您传递一些“大”的东西,例如“blob”,否则请使用“bindValue”。以上是关于PDO 准备状态与手动查询的结果不同的主要内容,如果未能解决你的问题,请参考以下文章
mysql pdo查询结果 int 变成结果string 解决