【问题标题】:mySQL PDO Prepared Statement Different Results from Non-Prepared StatementmySQL PDO Prepared Statement 结果与 Non-Prepared Statement 不同
【发布时间】:2016-03-09 19:18:31
【问题描述】:

我在 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

注意“行计数”在准备好的语句中为零。我盯着这个看的时间比我愿意承认的要长。谁能看到为什么一个返回结果而另一个没有?谢谢!

【问题讨论】:

  • 你的第一个代码体(如果它是你的实际代码)在某处包含语法错误,语法高亮显示是这样。它在哪里,我还不知道。
  • 我认为你不能这样做SELECT COUNT(*) as counted。请改用列。
  • 奇怪。我只用“CatID”替换了我的原始变量。我觉得不太容易辨认。
  • 好吧,它适用于未准备好的代码。我不能用准备好的声明来做到这一点?

标签: php mysql pdo prepared-statement


【解决方案1】:

问题是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);

【讨论】:

  • 旁注::interval HOUR) - OP 使用一系列不同的选项。他们将不得不将其更改为:interval DAY) 等以获得不同的选项。我认为他们想要动态地做到这一点。除非我在他们的方法中遗漏了什么。
  • @Fred-ii- 不,我在 $interval 的值中这样做,将天数乘以 24 小时/天。
  • 啊,是的。再次查看您的答案后,我接受了它。感谢您的推动 ;-)
  • 部分归功于@Your Common Sense。上面的代码工作,以及使用“fetchColumn()”来检测无结果状态。
【解决方案2】:

占位符不能代表查询的任意部分,只能代表完整的字符串或数字文字。

因此你不能绑定区间的一部分。

只要您在上面显示的代码中将您的区间列入白名单,您就可以并且必须坚持使用旧的区间方法。

【讨论】:

  • 啊! @你的常识。这是我怀疑的事情之一,但找不到明确的答案。那么,如何使用未准备的方式确定无结果条件?我不能使用 mysqi_num_rows 因为它是 PDO,不是吗?
  • 首先,您永远不需要像 PHP 中的 num rows 这样的函数。只需获取您的结果并查看是否已获取任何内容。无论哪种方式,我都不明白这样的功能与您的问题有何关系。如上所述,count(*) 查询总是返回一行
  • 顺便说一下,你的报错是错误的。您应该为 PDO 启用异常,但不应该捕获它们。详情请见phpdelusions.net/pdo#errors
  • 毫无疑问,这是我向 PDO 的有机迁移造成的。当没有返回任何内容时,我收到了一个错误。在过去,非 PDO 时间,我会使用 mysql_num_rows 来检查没有结果。感谢您的链接。看起来很有用。
【解决方案3】:

select count(*) 不可能返回 0 行。它将始终返回至少 一个 行,其中包含匹配/找到的行数。获得 0 行意味着您的查询完全失败,并且没有返回结果集,句号。

您是否在 PDO 中启用了异常?默认情况下,它会为失败“返回 false”,并且不会抛出异常,除非您明确启用它们。如果它们没有被启用,那么你的try/catch 就没有用了。

【讨论】:

  • 脚本中启用了异常。我是否必须以不同的方式启用 PDO 异常?
猜你喜欢
  • 2011-07-24
  • 2014-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-26
  • 2014-12-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多