试图参数化SQL LIMIT:offset,:display时出现PHP PDO错误?

试图参数化SQL LIMIT:offset,:display时出现PHP PDO错误?,php,mysql,pdo,rowcount,Php,Mysql,Pdo,Rowcount,此查询在phpMyAdmin中返回5个结果: SELECT * FROM tbl_product WHERE 1 ORDER BY last_update DESC LIMIT 0,5 在phpMyAdmin中返回count=12(这很好,因为有12条记录): 在我添加两个变量(偏移量、显示量)之前,这个函数工作得很好,但是现在它不工作了,打印出的变量给了我偏移量=0,显示量=5(因此仍然限制0,5) 它不起作用,因为我的dbrowsont(…)方法返回空字符串(愚蠢的PDOStatement

此查询在phpMyAdmin中返回5个结果:

SELECT * FROM tbl_product WHERE 1 ORDER BY last_update DESC LIMIT 0,5
在phpMyAdmin中返回count=12(这很好,因为有12条记录):

在我添加两个变量(偏移量、显示量)之前,这个函数工作得很好,但是现在它不工作了,打印出的变量给了我偏移量=0,显示量=5(因此仍然
限制0,5

它不起作用,因为我的
dbrowsont(…)
方法返回空字符串(愚蠢的
PDOStatement::fetchColumn
),所以我将其更改为使用
PDO::FETCH_ASSOC
返回计数,并且它返回计数=0

以下是进行行计数的函数:

function dbRowsCount($sql, $data) {
    global $db, $query;
    $regex = '/^SELECT\s+(?:ALL\s+|DISTINCT\s+)?(?:.*?)\s+FROM\s+(.*)$/is';
    if (preg_match($regex, $sql, $output) > 0) {
        $query = $db->prepare("SELECT COUNT(*) AS count FROM {$output[1]}");
logErrors("Regex output: "."SELECT COUNT(*) AS count FROM {$output[1]}");
        $query->setFetchMode(PDO::FETCH_ASSOC);
        if ($data != null) $query->execute($data); else $query->execute();
        if (!$query) {
            echo "Oops! There was an error: PDOStatement returned false.";
            exit;
        }
        $result = $query->fetch();
        return (int)$result["count"];
    } else {
logErrors("Regex did not match: ".$sql);
    }
    return -1;
}
我的错误日志提供程序的以下输出:

正则表达式输出:选择COUNT(*)作为tbl_产品的计数,其中1个订单按上次更新描述限制
getProducts(0,5)返回了0行

正如您所看到的,SQL没有出现错误,方法输入变量如预期的那样为0和5

有人知道出了什么问题吗

更新 根据建议,我确实尝试直接执行查询,它返回了正确的结果:

function dbDebugTest() {
    global $db;
    $stmt = $db->query("SELECT COUNT(*) AS count FROM tbl_product WHERE 1 ORDER BY last_update LIMIT 0,5;");
    $result = $stmt->fetch();
    $rows = (int)$result["count"];
    logErrors("dbDebugTest() returned rows=".$rows);
}
输出:

> dbDebugTest() returned rows=12
> Data: 0,5
根据另一个建议,我改变了=空到==null,并且我还打印了$data数组:

logErrors("Data: ".implode(",",$data));
if ($data !== null) $query->execute($data); else $query->execute();
输出:

> dbDebugTest() returned rows=12
> Data: 0,5
但是,dbRowsCount($sql,$data)仍然会为此查询返回0行

更新2 下面的实现建议允许我在绑定值后输出查询,我发现函数将在$query->execute($data)之后停止,因此不会打印输出,尽管自定义类适用于我程序中的每一个其他查询

更新代码:

function dbRowsCount($sql, $data) {
    global $db, $query;
    $regex = '/^SELECT\s+(?:ALL\s+|DISTINCT\s+)?(?:.*?)\s+FROM\s+(.*)$/is';
    if (preg_match($regex, $sql, $output) > 0) {
        $query = $db->prepare("SELECT COUNT(*) AS count FROM {$output[1]}");
logErrors("Regex output: "."SELECT COUNT(*) AS count FROM {$output[1]}");
        $query->setFetchMode(PDO::FETCH_ASSOC);
logErrors("Data: ".implode(",",$data));
        $query->execute($data);
logErrors("queryString:".$query->queryString);
logErrors("_debugQuery():".$query->_debugQuery());
        if (!$query) {
            echo "Oops! There was an error: PDOStatement returned false.";
            exit;
        }
        $result = $query->fetch();
        return (int)$result["count"];
    } else {
logErrors("Regex did not match: ".$sql);
    }
    return -1;
}
输出:

> dbDebugTest() returned rows=12
> Data: 0,5
正则表达式输出:选择COUNT()作为tbl_product_类别的计数,其中id=
数据:5
queryString:从tbl_产品_类别中选择COUNT()作为计数,其中id=
_debugQuery():选择COUNT(*)作为tbl_product_类别中的COUNT,其中id=

正则表达式输出:选择COUNT(*)作为tbl_产品的计数,其中1个订单按上次更新描述限制
数据:0,5
//函数已停止,无法输出_debugQuery

更新3 因为我无法让自定义PDOStatement类提供一些输出,所以我想我应该重写
getProducts(…)
类,用命名占位符绑定参数

function getProducts($offset, $display) {
    $sql = "SELECT * FROM tbl_product WHERE 1 ORDER BY last_update DESC LIMIT :offset, :display;";
    $data = array(':offset'=>$offset, ':display'=>$display);
    $rows = dbRowsCount($sql, $data);
logErrors("getProducts(".$offset.",".$display.") returned ".$rows." rows.");
    if ($rows > 0) {
        dbQuery($sql, $data);
        return dbFetchAll();
    } else {
        return null;
    }
}
输出:

正则表达式输出:选择计数(*)作为tbl_产品的计数,其中1个订单按上次更新描述限制:偏移量,:显示
数据:0,5
//在$query->execute($data)之后仍然崩溃,因此
logErrors(“getProducts(“.$offset.”…)
没有打印出来

更新4 此dbDebugTest以前用于直接在SQL字符串中声明限制值0,5。现在我已对其进行了更新,以正确绑定参数:

function dbDebugTest($offset, $display) {
    logErrors("Beginning dbDebugTest()");
    global $db;
    $stmt = $db->prepare("SELECT COUNT(*) AS count FROM tbl_product WHERE 1 ORDER BY last_update LIMIT :offset,:display;");
    $stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
    $stmt->bindParam(':display', $display, PDO::PARAM_INT);
    if ($stmt->execute()) {
      $result = $stmt->fetch();
      $rows = (int)$result["count"];
      logErrors("dbDebugTest() returned rows=".$rows);
    } else {
      logErrors("dbDebugTest() failed!");
    }
}
函数崩溃,仅此为输出:

正在开始dbDebugTest()

更新5 根据打开错误的建议(默认情况下它们是关闭的),我这样做了:

$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
这本身就使得更新4中的dbDebugTest()能够工作

正在开始dbDebugTest() dbDebugTest()返回的行数=12

现在在我的Web服务器日志中生成了一个错误:

[警告]mod_fcgid:stderr:PHP致命错误:
未捕获的异常“PDOException”,消息为“SQLSTATE[42000]:
语法错误或访问冲突:1064您的SQL语法有错误;
查看与您的MySQL服务器版本对应的手册,了解要使用的正确语法
在第1行的“0”、“5”附近
在/home/linweb09/b/example.com-1050548206/user/my_program/database/dal.php:36中

第36行引用了
dbrowsont(…)
方法,该行是
$query->execute($data)

因此,另一种方法
getProducts(…)
仍然不起作用,因为它使用了这种绑定数据的方法,参数变成了“0”和“5”(这是一个bug吗?)。有点烦人,但我必须在我的dal.php中创建一个新方法,允许我以更严格的方式绑定参数-使用
bindParam


特别感谢@Travesty3和@eggyal的帮助!!非常感谢。

您正在测试
$data
是否为
NULL
,并使用相等运算符,而不是标识运算符(有关各种比较运算符如何处理
NULL
值的更多信息,请参阅)。您需要使用身份测试
===
/
!==
,或者调用


正如上面提到的@Travesty3,要测试数组是否为空,请使用。

根据问题中的更新2,如果执行在
execute
语句后停止,则查询似乎失败。查看后,默认的错误处理设置似乎是PDO::ERRMODE\u SILENT,这将导致您执行的行为我在看

这很可能是由于LIMIT子句中的数字在作为参数传入时被放在单引号中,就像在中发生的那样

该帖子的解决方案是使用该方法将参数指定为整数,因此您可能需要做类似的事情

看起来您还应该使用try-catch块执行查询,以便捕获MySQL错误


bindValue方法:

if ($data !== null)
{
    for ($i=0; $i<count($data); $i++)
        $query->bindValue($i+1, $data[$i], PDO::PARAM_INT);
    $query->execute($data);
}
else
    $query->execute();
if($data!==null)
{
对于($i=0;$ibindValue($i+1,$data[$i],PDO::PARAM_INT);
$query->execute($data);
}
其他的
$query->execute();

您是否尝试手动运行查询?如使用
$db->query(xxx)
没有任何参数或包装函数?那么它能工作吗?我不明白为什么会被否决?@kuba我没有这样做,因为我直接在phpMyAdmin中尝试了SQL,所以我认为它能工作,但我现在就去试试。@Ozzy:我也不明白否决票(你有我的+1)。你测试过
if($data!=null)吗
要查看执行采取的路径,是否应该使用