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 对的关联数组。
我在查询中收到 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 对的关联数组。