PHP PDO 和使用 SELECT COUNT(*) 的查询

标签 php mysql sql pdo count

我这里有一个非常奇怪的问题 - 这是一个小解决方法,用于解决 PDO 无法与 MySQL 结合返回 num_rows 的事实。

我可以通过 phpmyadmin 将此查询直接提供给数据库:

SELECT COUNT(*) AS COUNT
FROM ((
         (SELECT 'Key' AS tradeOrigin,
                 CONCAT(skti.tier, ' ', skty.type) AS trade,
                 CONCAT('Amount: ', t.sourceKeyAmount) AS tradeInfo,
                 'Platinum' AS tradeToOrigin,
                 t.destinationPlatinum AS tradeTo,
                 '' AS tradeToInfo,
                 u.ingame AS seller,
                 DAYSPASSED(added) AS daysPassed,
                 DATEDIFF(NOW(), added) AS sortingSince
          FROM trades t
          JOIN users u ON t.sourceItem = 1
          AND t.destinationItem = 1
          AND t.userId = u.userId
          AND t.sourceModId = 18
          JOIN keytiers skti ON t.sourceKeyTierId = skti.keyTierId
          JOIN keytypes skty ON t.sourceKeyTypeId = skty.keyTypeId)
       UNION ALL
         (SELECT 'Mod' AS tradeOrigin,
                 sm.name AS trade,
                 CONCAT('Level: ', IF(t.sourceModLevel = 0, 'Unranked', t.sourceModLevel)) AS tradeInfo,
                 'Platinum' AS tradeToOrigin,
                 t.destinationPlatinum AS tradeTo,
                 '' AS tradeToInfo,
                 u.ingame AS seller,
                 DAYSPASSED(added) AS daysPassed,
                 DATEDIFF(NOW(), added) AS sortingSince
          FROM trades t
          JOIN users u ON t.sourceItem = 2
          AND t.destinationItem = 1
          AND t.userId = u.userId
          AND t.sourceModId = 18
          JOIN mods sm ON t.sourceModId = sm.modId)) AS derived)

它将返回一行,其中包含 count 列和值 1,如预期

但是,当它需要通过我的框架时,它就会出错。

执行代码:

if (!empty($sql)) {
    try {
        echo $sql."<br><pre>";
        print_r($dataArray);
        echo "</pre>";
        $numrows = $dbh->num_rows($sql, $dataArray);
    } catch (PDOException $ex) {
//        echo $ex;
        error($ex);
    }
    //...

输出:

  (SELECT 'Key' AS tradeOrigin,
          CONCAT(skti.tier, ' ', skty.type) AS trade,
          CONCAT('Amount: ', t.sourceKeyAmount) AS tradeInfo,
          'Platinum' AS tradeToOrigin,
          t.destinationPlatinum AS tradeTo,
          '' AS tradeToInfo,
          u.ingame AS seller,
          DAYSPASSED(added) AS daysPassed,
          DATEDIFF(NOW(), added) AS sortingSince
   FROM trades t
   JOIN users u ON t.sourceItem = 1
   AND t.destinationItem = 1
   AND t.userId = u.userId
   AND t.sourceModId = :modId
   JOIN keytiers skti ON t.sourceKeyTierId = skti.keyTierId
   JOIN keytypes skty ON t.sourceKeyTypeId = skty.keyTypeId)
UNION ALL
  (SELECT 'Mod' AS tradeOrigin,
          sm.name AS trade,
          CONCAT('Level: ', IF(t.sourceModLevel = 0, 'Unranked', t.sourceModLevel)) AS tradeInfo,
          'Platinum' AS tradeToOrigin,
          t.destinationPlatinum AS tradeTo,
          '' AS tradeToInfo,
          u.ingame AS seller,
          DAYSPASSED(added) AS daysPassed,
          DATEDIFF(NOW(), added) AS sortingSince
   FROM trades t
   JOIN users u ON t.sourceItem = 2
   AND t.destinationItem = 1
   AND t.userId = u.userId
   AND t.sourceModId = :modId
   JOIN mods sm ON t.sourceModId = sm.modId)

Array
(
    [:modId] => 18
)

这进入(注意:$this->dbh是一个PDO实例):

/**
 * Returns the number of rows that this query has.
 * 
 * @param type $query   The input query
 * @param type $values  The values
 * @return type Number of rows
 */
public function num_rows($query, $values) {
    $newquery = "SELECT COUNT(*) AS count FROM (({$query}) AS derived)";
    echo $newquery;
    $statement = $this->query($newquery, $values);
    $i = $statement->fetch();
    echo "<pre>";
    print_r($i);
    echo "</pre>";
    return $i->count;
}

它回响:

SELECT COUNT(*) AS COUNT
FROM ((
         (SELECT 'Key' AS tradeOrigin,
                 CONCAT(skti.tier, ' ', skty.type) AS trade,
                 CONCAT('Amount: ', t.sourceKeyAmount) AS tradeInfo,
                 'Platinum' AS tradeToOrigin,
                 t.destinationPlatinum AS tradeTo,
                 '' AS tradeToInfo,
                 u.ingame AS seller,
                 DAYSPASSED(added) AS daysPassed,
                 DATEDIFF(NOW(), added) AS sortingSince
          FROM trades t
          JOIN users u ON t.sourceItem = 1
          AND t.destinationItem = 1
          AND t.userId = u.userId
          AND t.sourceModId = :modId
          JOIN keytiers skti ON t.sourceKeyTierId = skti.keyTierId
          JOIN keytypes skty ON t.sourceKeyTypeId = skty.keyTypeId)
       UNION ALL
         (SELECT 'Mod' AS tradeOrigin,
                 sm.name AS trade,
                 CONCAT('Level: ', IF(t.sourceModLevel = 0, 'Unranked', t.sourceModLevel)) AS tradeInfo,
                 'Platinum' AS tradeToOrigin,
                 t.destinationPlatinum AS tradeTo,
                 '' AS tradeToInfo,
                 u.ingame AS seller,
                 DAYSPASSED(added) AS daysPassed,
                 DATEDIFF(NOW(), added) AS sortingSince
          FROM trades t
          JOIN users u ON t.sourceItem = 2
          AND t.destinationItem = 1
          AND t.userId = u.userId
          AND t.sourceModId = :modId
          JOIN mods sm ON t.sourceModId = sm.modId)) AS derived)

stdClass Object
(
    [count] => 0
)

哪个调用:

/**
 * Can be called to create a query. Use either unnamed or named placeholders for the prepared statements.
 * 
 * Example: $dbh->query("INSERT INTO table (data1, data2) VALUES(?, ?)", array($data1, $data2));
 * 
 * @param type $query   The input query, including unnamed or named placeholders
 * @param type $values  The input values. If it's not an array, then it will be an one-element array
 * @return type The statement constructed by this query
 */
public function query($query, $values = array()) {
    if (!is_array($values)) {
        $values = array($values);
    }
    $statement = $this->dbh->prepare($query);
    $statement->setFetchMode(PDO::FETCH_OBJ);
    if (is_assoc($values)) {
        foreach ($values as $key => $value) {
            $statement->bindValue($key, $value);
        }
    }
    else {
        $i = 1;
        foreach ($values as $value) {
            $statement->bindValue($i++, $value);
        }
    }
    $statement->execute();
    return $statement;
}

query 方法在过去已被证明是有效的,而且奇怪的是,num_rows 确实适用于其他一些任意查询,该查询正确返回 6 作为计数。

我真的被困在这里,不知道发生了什么,请帮助我。

更新:

显然是一个设置向我介绍了这个问题:$this->dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

但是我仍然想知道为什么它会导致问题,因为我不能只是禁用它,因为我将它用于 LIMIT 子句,否则会失败(关于此事有很多 SO 帖子)。帖子示例如下:How to apply bindValue method in LIMIT clause?

最佳答案

根据评论中的讨论,您现在似乎有了足够的信息可以继续:您的 PDO 设置正在阻止您的绑定(bind)工作。

您说您正在使用该设置来使 LIMIT 工作 - 我猜测具体绑定(bind)到 LIMIT。通常不能这样做,因为绑定(bind)仅针对参数值(即在 WHERE 子句中),而 LIMIT 子句不被视为参数。您可以用另一种方式重写绑定(bind)的 LIMIT 查询吗?

最后,根据注释,确保您使用的任何别名都是小写的,并且不是保留字。您可能可以不区分大小写地使用这些,但无论如何,代码约定都是好的!

关于PHP PDO 和使用 SELECT COUNT(*) 的查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20857662/

相关文章:

mysql - 将大型 CSV 文件导入 MySQL Workbench

mysql - 表格行或列

mysql - 按类型返回每个月的用户数

php - 尽管 --prefer-dist 标志, Composer 依赖项的更新缓慢

php - PHP 中全局变量和函数参数之间的优点/缺点?

MySQL 错误 1241 : Operand should contain 1 column(s)

mysql - 为什么 mySQL 触发器不保存?

mysql - 如何合并这两个 MySQL Select 查询?

php - MySQL 身份验证在 php 上失败,但在 phpmyadmin 中失败

php - 从 S3 帐户将视频推送到 YouTube 成功,但视频永远是 "processing"