mySQL PDO 准备语句与非准备语句的不同结果
mySQL PDO Prepared Statement Different Results from Non-Prepared Statement
我在 PDO 方面的经验有些有限,而且我已经坚持了一段时间。问题是,当我 运行 代码未准备好时(因为这已被证明是我可以调试 PDO 的唯一方法),我得到了我想要的结果。当我 运行 它作为准备好的语句时,我得到不同的结果。见下文:
未准备代码:
$interval = array("hourly" => "1 HOUR", "daily" => "1 DAY", "weekly" => "7 DAY", "monthly" => "30 DAY", "yearly" => "1 YEAR");
$intervalString = "INTERVAL " . $interval[$p_sLimitType];
$SQL = "SELECT COUNT(*) as `counted` FROM tbl_transaction" .
" WHERE type='" . $p_sPostType . "'" .
" AND catID=" . $p_nCatID .
" AND serviceID=" . $p_nServiceID .
" AND serviceIdentity=" . $p_nServiceUserID .
" AND timestamp BETWEEN DATE_SUB(NOW(), $intervalString . ") AND NOW()";
$theQuery = $DB->Query($SQL);
echo "\r\n\r\nQuery:";
print_r($theQuery);
echo "\r\nResult:";
$result = $theQuery->fetch(PDO::FETCH_ASSOC);
print_r($result);
未准备结果:
Query:PDOStatement Object
(
[queryString] => SELECT COUNT(*) as `counted` FROM tbl_transaction WHERE type='pudding' AND catID=13 AND serviceID=1 AND serviceIdentity=3324848959 AND timestamp BETWEEN DATE_SUB(NOW(), INTERVAL 1 DAY) AND NOW()
)
Result:Array
(
[counted] => 15
)
现在准备好的代码:
$interval = array("hourly" => "1 HOUR", "daily" => "1 DAY", "weekly" => "7 DAY", "monthly" => "30 DAY", "yearly" => "1 YEAR");
$intervalString = "INTERVAL " . $interval[$p_sLimitType];
$SQL = "SELECT COUNT(*) as `counted` FROM tbl_transaction" .
" WHERE type=:postType" .
" AND catID=:catID" .
" AND serviceID=:serviceID" .
" AND serviceIdentity=:serviceIdentity" .
" AND timestamp BETWEEN DATE_SUB(NOW(), :interval) AND NOW()";
// Execute the statement
try {
$stmt = $DB->prepare($SQL);
$stmt->bindParam(':postType', $p_sPostType, PDO::PARAM_STR, 30);
$stmt->bindParam(':catID', $p_nCatID, PDO::PARAM_INT);
$stmt->bindParam(':serviceID', $p_nServiceID, PDO::PARAM_INT);
$stmt->bindParam(':serviceIdentity', $p_nServiceUserID, PDO::PARAM_INT);
$stmt->bindParam(':interval', $intervalString, PDO::PARAM_STR, 30);
$result = $stmt->execute();
} catch(PDOException $e) {
mm_die($e->getMessage());
}
echo "\r\n$SQL = $SQL";
// echo "\r\n$p_nLimitValue = $p_nLimitValue\r\n";
echo "\r\nRow Count: " .$stmt->rowCount() . "\r\n";
准备结果:
$SQL = SELECT COUNT(*) as `counted` FROM tbl_transaction WHERE type=:postType AND siloID=:siloID AND serviceID=:serviceID AND serviceIdentity=:serviceIdentity AND timestamp BETWEEN DATE_SUB(NOW(), :interval) AND NOW()
Row Count: 0
注意 "Row Count" 在准备好的语句中为零。我盯着它看的时间比我愿意承认的要长。谁能看出为什么一个 returns 结果而另一个没有?谢谢!
占位符不能表示查询的任意部分,只能表示完整的字符串或数字文字。
因此不能绑定区间的一部分。
只要您在代码中将间隔列入白名单,就可以并且必须坚持使用旧的间隔方法。
select count(*)
到 return 0 行是不可能的。它总是 return 至少 一个 行,包含 matched/found 行的计数。获得 0 行意味着您的查询完全失败,并且没有 return 结果集,期间。
您是否在 PDO 中启用了例外?默认情况下它会 "return false" 失败,除非您明确启用它们,否则不会抛出异常。如果它们没有启用,那么你的 try/catch
就没用了。
问题是 DATE_SUB()
的第二个参数必须是一个间隔,但您提供的是一个字符串。字符串"INTERVAL 1 HOUR
不会自动转换成对应的区间。您只能为 INTERVAL
表达式的数字部分使用占位符,不能为关键字使用占位符。
从关联数组中取出时间单位,并将所有内容表示为小时。
$interval = array("hourly" => 1, "daily" => 24, "weekly" => 7*24, "monthly" => 30*24, "yearly" => 365*24);
那么你可以这样做:
$SQL = "SELECT COUNT(*) as `counted` FROM tbl_transaction" .
" WHERE type=:postType" .
" AND catID=:catID" .
" AND serviceID=:serviceID" .
" AND serviceIdentity=:serviceIdentity" .
" AND timestamp BETWEEN DATE_SUB(NOW(), INTERVAL :interval HOUR) AND NOW()";
和
$stmt->bindParam(':interval', $interval[$p_sLimitType], PDO::PARAM_INT);
我在 PDO 方面的经验有些有限,而且我已经坚持了一段时间。问题是,当我 运行 代码未准备好时(因为这已被证明是我可以调试 PDO 的唯一方法),我得到了我想要的结果。当我 运行 它作为准备好的语句时,我得到不同的结果。见下文:
未准备代码:
$interval = array("hourly" => "1 HOUR", "daily" => "1 DAY", "weekly" => "7 DAY", "monthly" => "30 DAY", "yearly" => "1 YEAR");
$intervalString = "INTERVAL " . $interval[$p_sLimitType];
$SQL = "SELECT COUNT(*) as `counted` FROM tbl_transaction" .
" WHERE type='" . $p_sPostType . "'" .
" AND catID=" . $p_nCatID .
" AND serviceID=" . $p_nServiceID .
" AND serviceIdentity=" . $p_nServiceUserID .
" AND timestamp BETWEEN DATE_SUB(NOW(), $intervalString . ") AND NOW()";
$theQuery = $DB->Query($SQL);
echo "\r\n\r\nQuery:";
print_r($theQuery);
echo "\r\nResult:";
$result = $theQuery->fetch(PDO::FETCH_ASSOC);
print_r($result);
未准备结果:
Query:PDOStatement Object
(
[queryString] => SELECT COUNT(*) as `counted` FROM tbl_transaction WHERE type='pudding' AND catID=13 AND serviceID=1 AND serviceIdentity=3324848959 AND timestamp BETWEEN DATE_SUB(NOW(), INTERVAL 1 DAY) AND NOW()
)
Result:Array
(
[counted] => 15
)
现在准备好的代码:
$interval = array("hourly" => "1 HOUR", "daily" => "1 DAY", "weekly" => "7 DAY", "monthly" => "30 DAY", "yearly" => "1 YEAR");
$intervalString = "INTERVAL " . $interval[$p_sLimitType];
$SQL = "SELECT COUNT(*) as `counted` FROM tbl_transaction" .
" WHERE type=:postType" .
" AND catID=:catID" .
" AND serviceID=:serviceID" .
" AND serviceIdentity=:serviceIdentity" .
" AND timestamp BETWEEN DATE_SUB(NOW(), :interval) AND NOW()";
// Execute the statement
try {
$stmt = $DB->prepare($SQL);
$stmt->bindParam(':postType', $p_sPostType, PDO::PARAM_STR, 30);
$stmt->bindParam(':catID', $p_nCatID, PDO::PARAM_INT);
$stmt->bindParam(':serviceID', $p_nServiceID, PDO::PARAM_INT);
$stmt->bindParam(':serviceIdentity', $p_nServiceUserID, PDO::PARAM_INT);
$stmt->bindParam(':interval', $intervalString, PDO::PARAM_STR, 30);
$result = $stmt->execute();
} catch(PDOException $e) {
mm_die($e->getMessage());
}
echo "\r\n$SQL = $SQL";
// echo "\r\n$p_nLimitValue = $p_nLimitValue\r\n";
echo "\r\nRow Count: " .$stmt->rowCount() . "\r\n";
准备结果:
$SQL = SELECT COUNT(*) as `counted` FROM tbl_transaction WHERE type=:postType AND siloID=:siloID AND serviceID=:serviceID AND serviceIdentity=:serviceIdentity AND timestamp BETWEEN DATE_SUB(NOW(), :interval) AND NOW()
Row Count: 0
注意 "Row Count" 在准备好的语句中为零。我盯着它看的时间比我愿意承认的要长。谁能看出为什么一个 returns 结果而另一个没有?谢谢!
占位符不能表示查询的任意部分,只能表示完整的字符串或数字文字。
因此不能绑定区间的一部分。
只要您在代码中将间隔列入白名单,就可以并且必须坚持使用旧的间隔方法。
select count(*)
到 return 0 行是不可能的。它总是 return 至少 一个 行,包含 matched/found 行的计数。获得 0 行意味着您的查询完全失败,并且没有 return 结果集,期间。
您是否在 PDO 中启用了例外?默认情况下它会 "return false" 失败,除非您明确启用它们,否则不会抛出异常。如果它们没有启用,那么你的 try/catch
就没用了。
问题是 DATE_SUB()
的第二个参数必须是一个间隔,但您提供的是一个字符串。字符串"INTERVAL 1 HOUR
不会自动转换成对应的区间。您只能为 INTERVAL
表达式的数字部分使用占位符,不能为关键字使用占位符。
从关联数组中取出时间单位,并将所有内容表示为小时。
$interval = array("hourly" => 1, "daily" => 24, "weekly" => 7*24, "monthly" => 30*24, "yearly" => 365*24);
那么你可以这样做:
$SQL = "SELECT COUNT(*) as `counted` FROM tbl_transaction" .
" WHERE type=:postType" .
" AND catID=:catID" .
" AND serviceID=:serviceID" .
" AND serviceIdentity=:serviceIdentity" .
" AND timestamp BETWEEN DATE_SUB(NOW(), INTERVAL :interval HOUR) AND NOW()";
和
$stmt->bindParam(':interval', $interval[$p_sLimitType], PDO::PARAM_INT);