PDO和PHP / MySQL:PDO编写的语句有什么问题?

时间:2012-07-27 22:00:15

标签: php mysql pdo

我知道这个标题听起来很荒谬,但我已经做了几个小时的研究,现在却发现PDO最终没有明显的解决方案......我致力于为一个开放。我也愿意接受我的代码存在缺陷。

使用PHP 5.2 / Ubuntu,此代码有效(不使用预处理语句/打开注入):

$sql ="SELECT COUNT(*) FROM property p
INNER JOIN property_attribute pa ON p.property_id = pa.property_id
INNER JOIN property_area pc ON p.property_id = pc.property_id
WHERE pa.attribute_value_id
    IN (
        SELECT av.attribute_value_id
        FROM attribute_value av
        INNER JOIN attribute a ON av.attribute_id = a.attribute_id
        WHERE a.name LIKE '$attributes'
        AND av.value LIKE '$values'
    ) 
ORDER BY p.price ASC";
$params = array();
$rHowManyPages = Listings::HowManyPages($sql, $params);

然而,使用PDO精心准备的陈述:

$sql ='SELECT COUNT(*) FROM property p
INNER JOIN property_attribute pa ON p.property_id = pa.property_id
INNER JOIN property_area pc ON p.property_id = pc.property_id
WHERE pa.attribute_value_id
    IN (
        SELECT av.attribute_value_id
        FROM attribute_value av
        INNER JOIN attribute a ON av.attribute_id = a.attribute_id
        WHERE a.name LIKE :attributes
        AND av.value LIKE :values
    ) 
ORDER BY p.price ASC';
$params = array(':attributes' => $attributes, ':values' => $values);
$rHowManyPages = Listings::HowManyPages($sql, $params);

它有效,有点。这是Spartanic疯狂部分:传递相同数据的刷新中有1个,PDO给出了这个错误:

TEXT: SQLSTATE[HY093]: Invalid parameter number

这是随机的!怎么样和为什么?

1 个答案:

答案 0 :(得分:5)

为命名参数提供的值之一是否可能包含问号?我遇到了一个问题,但那是很久以前的事了。 (我当然希望他们现在可以解决这个问题。)

在我有限的经验中,PDO对“命名参数”的支持有些粗略。

首先,您不能在语句的多个位置使用相同的命名参数,每个命名参数的占位符名称必须是唯一的,并且只能使用一次。这就是命名论证的一个重大好处。

我相信我遇到的问题是字符中的问题,并且无法多次引用命名参数(我还没有证实这一点)是由于PDO“命名参数”支持是一个螺栓 - 后来支持位置论证;基本上,看起来“命名参数”被转换为位置参数。

当命名参数包含下划线字符时,我也遇到了一些困难。

我的解决方法是(ACCCKKK!)使用位置参数而不是命名参数。

(尽管我不喜欢使用位置参数,但它对我有用。)

(我发现您所显示的代码中没有任何错误可以解释观察到的行为。显然,还有其他代码没有显示。)

此外,您可能希望验证您的$params数组仅包含两个元素;当我的数组有一个“额外”不匹配的元素时,我有相同的错误消息。然后,在我的代码中,我退回到使用标量,并分别绑定每个,而不是让PDO捣乱它。 (对我来说不是问题,这是我在Perl DBI中过于熟悉的模式。我没有调试问题,而是解决了这些问题。)


注意:通过位置参数,我的意思是使用问号代替名称:

 $sql = " ...
  WHERE a.name LIKE ?
    AND av.value LIKE ?
 ... ";

$sth->bindParam(1, $attributes);
$sth->bindParam(2, $values);