You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

PHP PDO用bindParam仍报SQLSTATE[HY093]参数数量错误的解决咨询

解决PDO中重复参数标记导致的SQLSTATE[HY093]错误

你遇到的这个问题其实挺常见的——虽然你用了bindParam而不是直接给execute传数组,但很多PDO驱动(比如MySQL的默认驱动)并不支持在预处理语句中重复使用同名参数标记,不管你用哪种绑定方式,都会触发Invalid parameter number错误。

问题根源

PDO的原生预处理(也就是关闭EMULATE_PREPARES时)会把预处理语句发送给数据库服务器解析,这时数据库会把每个:user:offset都当成独立的占位符。比如你的第一条SQL里:user出现了两次,:offset一次,总共需要3个参数,但你只绑定了2个(useroffset各一次),自然就参数数量不匹配了。

之前你用同一个query函数没报错,大概率是当时的SQL没有重复参数,或者你的PDO连接默认开启了模拟预处理。

解决方案

下面给你几个实用的解决办法,按推荐程度排序:

1. 开启PDO的模拟预处理(最简便)

当开启PDO::ATTR_EMULATE_PREPARES时,PDO会在客户端完成参数替换,而不是把预处理语句发给数据库。这时重复的参数标记会被正确替换多次,不会有参数数量问题。

你只需要在初始化PDO连接的时候添加这个属性:

// 假设你是这样初始化PDO的,修改成下面的样子
$this->_pdo = new PDO(
    'mysql:host=your_host;dbname=your_db;charset=utf8mb4',
    'username',
    'password',
    [
        PDO::ATTR_EMULATE_PREPARES => true,
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // 推荐开启错误模式,方便调试
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ // 可选,和你的fetchAll保持一致
    ]
);

这个方法不需要修改你的SQL和query函数,直接解决问题。

2. 修改SQL避免重复参数

如果你不想开启模拟预处理,可以调整SQL语句,把重复的参数合并成一次引用。比如第一条SQL可以改成:

SELECT upload_id FROM uploads 
WHERE upload_artist IN (
    SELECT following FROM followers WHERE follower = :user
    UNION ALL SELECT :user -- 把OR的条件合并到IN里
) 
AND upload_private = 0 
AND upload_published = 1 
ORDER BY upload_date desc 
LIMIT :offset, 7

这样SQL里:user只出现一次,:offset一次,参数数量就匹配了。第二条SQL同理,把OR repost_user = :user合并到IN子查询里。

3. 为每个重复参数单独绑定(繁琐但原生)

如果上面两种方法都不想用,你可以在$params里为每个重复的参数添加条目,比如第一条SQL里:user出现两次,就把$params改成:

$params = [
    "user" => $user_id,
    "user2" => $user_id,
    "offset" => $offset
];

同时修改SQL里的第二个:user:user2

SELECT upload_id FROM uploads 
WHERE upload_artist IN (SELECT following FROM followers WHERE follower = :user) 
OR upload_artist = :user2 
AND upload_private = 0 
AND upload_published = 1 
ORDER BY upload_date desc 
LIMIT :offset, 7

但这种方法需要修改SQL和参数数组,比较繁琐,不推荐。

验证修改

修改完PDO属性或者SQL后,再运行你的代码,应该就不会再出现HY093错误了。如果还是有问题,可以检查一下PDO连接的属性是否正确设置,或者SQL里的参数标记是否和绑定的参数名完全匹配。

内容的提问来源于stack exchange,提问作者Grover

火山引擎 最新活动