2014-12-27 34 views
3

我正在使用PHP和PDO准备语句来访问数据库。我有我要执行这个准备好的查询(通过一个foreach循环多次,但我没有看到,影响这真的):PDO准备的状态与手动查询的结果不一致

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); 

此执行,但奇怪的是,它会插入值的行(2,2)到forum_access。真正奇怪的是,当我运行变量的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。

+0

你可以导出准备的语句本身吗? – 2014-12-27 16:37:48

+1

你检查过参数的顺序吗?可能是错的。命名参数会更好 – kranthi117 2014-12-27 16:43:47

回答

2

我有点解决自己的问题。看起来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 

而且瞧,这实际上是有效的。

我仍然不确定为什么它应该工作。但我的直接关注是获得一个工作的应用程序,所以目前我很满意。

非常感谢您的帮助,并且很抱歉打扰了我可以解决的事情。

1

更改此

$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(); 
+1

这只会使代码更加冗长。我不明白为什么它应该有所作为: - ? – 2014-12-27 20:30:48

+0

除非必须,否则请勿使用“bindParam”。使用'bindValue',除非你传递'blob'等'大'。 – 2014-12-28 00:46:59

+0

正如所料,完整的语句是$ stmt-> bindParam(1,$ value_1);等等... – 2014-12-28 16:49:53

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(); 
+1

您的建议是切换到指定的地方所有者?你能否详细说明这将如何改变? – 2014-12-27 20:29:45

+0

不幸的是,这个解决方案和Peter Darmis提出的解决方案似乎都无能为力。我也尝试将我的应用导出到LAMP服务器(PHP:5.4.4,MySQL:5.5.38),导致错误1060:重复列名'?'。我不确定如何正确解释,但它似乎与WAMP服务器上的奇怪插入值有关。双 ?在插入中以某种方式混杂在准备好的语句解析中,这给LAMP上的错误和WAMP上奇怪的插入值。不过,仍然不知道如何解决这个问题。 – Danielle 2014-12-27 20:50:33

+1

请使用'bindValue'而不是'bindParam',然后使用'calculated'值。只对'blob'等大对象使用'bindParam'。如果您使用'bindParam',那么您必须**传递一个PHP变量,其中包含所需的值。这是自PHP 5.3以来改变了吗? – 2014-12-28 00:40:44