Php 重置PDO结果中的数组指针

Php 重置PDO结果中的数组指针,php,mysql,pdo,Php,Mysql,Pdo,我在从MySQL SELECT方法迁移到PDO方法时遇到困难。我想在获取的数组中迭代两次,两次都从第0行开始。在MySQL中,我将使用: mysql_data_seek($result,0); 使用PDO方法,我不确定如何完成同样的事情。下面的代码是我如何尝试做到这一点。第一个while循环工作正常,但第二个while循环不返回任何内容 $pdo = new PDO('mysql:host=' . $host . ';dbname='.$database, $username, $passwo

我在从MySQL SELECT方法迁移到PDO方法时遇到困难。我想在获取的数组中迭代两次,两次都从第0行开始。在MySQL中,我将使用:

mysql_data_seek($result,0);
使用PDO方法,我不确定如何完成同样的事情。下面的代码是我如何尝试做到这一点。第一个while循环工作正常,但第二个while循环不返回任何内容

$pdo = new PDO('mysql:host=' . $host . ';dbname='.$database, $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$stmt = $pdo->prepare('SELECT * FROM mytable WHERE active = 1 ORDER BY name ASC');
$stmt->setFetchMode(PDO::FETCH_ASSOC);
$stmt->execute();

while($row = $stmt->fetch())
{
    //do something starting with row[0]
}
while($row = $stmt->fetch())
{
    //do something else starting with row[0]
}

将结果保存到数组中,然后循环该数组两次

$pdo = new PDO('mysql:host=' . $host . ';dbname='.$database, $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$stmt = $pdo->prepare('SELECT * FROM mytable WHERE active = 1 ORDER BY name ASC');
$stmt->setFetchMode(PDO::FETCH_ASSOC);
$stmt->execute();

$rows = $stmt->fetchAll();

foreach ($rows as $r) {
    // first run
}

foreach ($rows as $r) {
    // seconds run
}
所以当它退出第一个元素时,它已经到达结果集的最后一个元素 这就是为什么第二个while什么也不返回


使用fetchAll存储所有结果,然后进行检查。

有时存储fetchAll()的结果不是一个选项。相反,您可以在像这样调用fetchAll()之前克隆pdo对象

if($stmt->fetchColumn() >= 0)
{
    $stmt->execute(); //Reset cursor
    while($rs = $stmt->fetchObject())
    {
        echo "Data: ".$rs->data;
    }
}
else
{
    echo '0';
}
$pdo_copy = clone $pdo;

$num_rows = count($pdo_copy->fetchAll());

现在我仍然可以使用pdo对象执行诸如fetchObject()之类的语句

根据php手册,您可以多次发出查询,如果使用PDO::prepare()准备PDOStatement对象,则可以多次调用PDOStatement::execute()发出该语句。 所以你的代码看起来是这样的

$stmt = $pdo->prepare('SELECT * FROM mytable WHERE active = 1 ORDER BY name ASC');
$stmt->setFetchMode(PDO::FETCH_ASSOC);

//First execute
$stmt->execute();
while($row = $stmt->fetch())
{
    //do something starting with row[0]
}

//Second execute
$stmt->execute();
while($row = $stmt->fetch())
{
    //do something else starting with row[0]
}

来源:

您需要通过在prepare中提供
PDO::CURSOR\u SCROLL
作为选项来告诉语句它必须是可滚动的。然后使用
PDO::FETCH_ORI_FIRST
在到达终点后再次到达第一个元素,以便重新开始

完整代码:

$pdo = new PDO('mysql:host=' . $host . ';dbname='.$database, $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

//Making cursor scrollable
$options = array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL);
$stmt = $pdo->prepare('SELECT * FROM mytable WHERE active = 1 ORDER BY name ASC',
                $options);

$stmt->setFetchMode(PDO::FETCH_ASSOC);
$stmt->execute();

while($row = $stmt->fetch())
{
    //do something starting with row[0]
}

//For the first row we use PDO::FETCH_ORI_FIRST 
//to get the first element again. This will also 
//move the cursor to that element
$first = true; 
while($row = $stmt->fetch(null, $first ? PDO::FETCH_ORI_FIRST : PDO::FETCH_ORI_NEXT)))
{
    $first = false;
    //do something else starting with row[0]
}

另一种解决方案是,如果您再次对结果queryString运行查询并获取:

public function fetch_again( $query_result, $fetch_type='fetch' )
{
    return $this->pdo->query($query_result->queryString)->$fetch_type();
}

哇!这似乎是显而易见的。不知道为什么我一直坚持使用while循环。谢谢你踢我的头!因为您忽略了。在处理大型结果集时,这不是一个好主意。所有数据都将存储在数组中。你能在答案的文本中解释一下吗?OP想要在获取的数组中迭代两次。我只能在代码中看到一个循环。那么,您的代码在多大程度上解决了OP问题?我给了您+1,这是正确的答案,我们不希望fetchAll()有几千行,但问题是“在PDO结果中重置数组指针”:这确实会将光标重置到第一行,谢谢。如果你非常确定你正在处理选择的。。。在我的例子中,我用它来调试所有的数据库查询,所以在调试模式下插入总是重复的,我花了一段时间才弄清楚原因。@Robert这个答案真的很奇怪。如果您需要发出相同的select查询,多次返回一个巨大的结果集,那么您正在做一些非常奇怪的事情。应该重新考虑你的方法,而不是使用这样的暴力。您可能需要在查询中添加WHERE或LIMIT子句以使其不同。@您的常识是这里的要点不同。在问题和解决方案中自我解释。在我发表评论时,我也遇到了类似的问题,标记为“好”的回复不是“好”的。WHERE子句存在,这不是重点,重点是重置指针。@YourCommonSense ok,因此修复标记为良好的回复,因为它不起作用。我不能编辑我的原始评论,否则我会添加“使用小型数据库”,这是我的情况,不幸的是他们是3年前,所以我甚至不知道他们是否修复了原始回复。当时,此答复有效,而标记为良好的则无效。“致命错误:未捕获错误:尝试克隆类PDO语句的不可克隆对象”
public function fetch_again( $query_result, $fetch_type='fetch' )
{
    return $this->pdo->query($query_result->queryString)->$fetch_type();
}