PDO MYSQL HY093(参数个数错误)下发错误

PDO MYSQL HY093 (wrong number of parameters) issued incorrectly

我在查询中收到 HY093(参数计数不匹配)SQLSTATE,我认为不存在不匹配。

下面我有一个完整的 PHP 脚本来重现错误。 (当然,需要更改数据库凭据。)在该脚本中,SELECT 语句中存在九个问号,搜索数组中有 9 个值,所有值均针对此测试进行了硬编码。然而,SELECT returns false(不按预期抛出异常)和 SQLSTATE 值为 HY093,这我的研究告诉我参数数量不正确。

我的第二个失望是这不会引发错误,但主要是我不知道如何查询这个 table。

任何可能导致此问题的建议?或者还需要哪些其他信息才能确定问题?

Linux velmicro 5.13.0-40-generic #45~20.04.1-Ubuntu SMP 4 月 4 日星期一 09:38:31 UTC 2022 x86_64

PHP 版本 7.4.3

mysql 版本为 8.0.24

UBUNTU VERSION="20.04.3 LTS (Focal Fossa)"

#! /usr/bin/php
<?php

$pdoOptions = [ PDO::ATTR_EMULATE_PREPARES   => false // no emulation mode for "real" prepared stmts
            ,  PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION // Errors cause exception
            ,  PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC // Default fetch mode
            ,  PDO::MYSQL_ATTR_FOUND_ROWS   => true
            ,  PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true
            ] ;

$pdo = new PDO('mysql:host=hostname.org.com;dbname=mainDb', 'username', 'password', $pdoOptions) ;


$pdo->exec("DROP TABLE IF EXISTS emotes") ;

$pdo->exec(<<<EOS
                CREATE TABLE emotes (
                    id int NOT NULL AUTO_INCREMENT
                   , emoteChar varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL
                   , epoch int NOT NULL
                   , name varchar(64) NOT NULL
                   , image1 varchar(128) DEFAULT NULL
                   , image2 varchar(128) DEFAULT NULL
                   , shortcut1 varchar(64) DEFAULT NULL
                   , shortcut2 varchar(64) DEFAULT NULL
                   , shortcut3 varchar(64) DEFAULT NULL
                   , shortcut4 varchar(64) DEFAULT NULL
                   , shortcut5 varchar(64) DEFAULT NULL
                   , PRIMARY KEY (id)
                   , KEY charEffective (emoteChar,epoch)
                    )
                EOS ) ;


$sql = <<<EOS
            SELECT id
            FROM   emotes em
            WHERE  emoteChar = ?
               AND name = ?
               AND IFNULL(image1, '') = IFNULL(?, '')
               AND IFNULL(image2, '') = IFNULL(?, '')
               AND IFNULL(shortcut1, '') = IFNULL(?, '')
               AND IFNULL(shortcut2, '') = IFNULL(?, '')
               AND IFNULL(shortcut3, '') = IFNULL(?, '')
               AND IFNULL(shortcut4, '') = IFNULL(?, '')
               AND IFNULL(shortcut5, '') = IFNULL(?, '')
               AND NOT EXISTS (SELECT 1
                               FROM   emotes sub
                               WHERE  sub.emoteChar = em.emoteChar
                                  AND sub.epoch > em.epoch
                               )
            EOS ;
$findEmoteStmt = $pdo->prepare($sql) ;
$findValues = [   'emoteChar' => 'x'
                , 'name' => 'name'
                , 'image1' => 'image1'
                , 'image2' => 'image2'
                , 'shortcut1' => 'shortcut1'
                , 'shortcut2' => 'shortcut2'
                , 'shortcut3' => 'shortcut3'
                , 'shortcut4' => 'shortcut4'
                , 'shortcut5' => 'shortcut5'
                         ] ;
$searchOk = $findEmoteStmt->execute( $findValues ) ;
if (! $searchOK) {
    printf("Could not search emoticon.  %d elements in the values.\nSQL='%s'\n  values=(%s)\n   error=(%s)\n"
               , count($findValues)
               , $findEmoteStmt->queryString
               , implode(',', $findValues)
               , implode(',', $findEmoteStmt->errorInfo())
                    ) ;
    }

执行:

> php test.php
Could not search emoticon.  9 elements in the values.
SQL='SELECT id
FROM   emotes em
WHERE  emoteChar = ?
   AND name = ?
   AND IFNULL(image1, '') = IFNULL(?, '')
   AND IFNULL(image2, '') = IFNULL(?, '')
   AND IFNULL(shortcut1, '') = IFNULL(?, '')
   AND IFNULL(shortcut2, '') = IFNULL(?, '')
   AND IFNULL(shortcut3, '') = IFNULL(?, '')
   AND IFNULL(shortcut4, '') = IFNULL(?, '')
   AND IFNULL(shortcut5, '') = IFNULL(?, '')
   AND NOT EXISTS (SELECT 1
                   FROM   emotes sub
                   WHERE  sub.emoteChar = em.emoteChar
                      AND sub.epoch > em.epoch
                   )'
  values=(x,name,image1,image2,shortcut1,shortcut2,shortcut3,shortcut4,shortcut5)
   error=(HY093,,)

f您有位置参数占位符 (?),但您的值位于关联数组中,PDO 会将其用于命名参数占位符。你不能混合这些不同的风格。

有两种方法可以解决此问题。使用一个或另一个修复程序(不能同时使用 :-)。

一个解决方法是将简单数组传递给 execute(),而不是关联数组:

$searchOk = $findEmoteStmt->execute( array_values($findValues) ) ;

另一个修复方法是使用与 $findValues 数组的键相对应的命名参数占位符,如下所示:

...    
WHERE  emoteChar = :emoteChar
   AND name = :name
...

其他参数也类似。

要点是,如果您使用位置参数,则传递一个简单的值数组。如果您使用命名参数,则传递 key/value 对的关联数组。