是否可以倒回 PDO 结果?

发布于 2024-07-09 04:34:38 字数 314 浏览 5 评论 0原文

我正在尝试为 PDO 语句的结果编写一个迭代器,但找不到任何回退到第一行的方法。 我想避免调用 fetchAll 和存储所有结果数据的开销。

// first loop works fine
foreach($statement as $result) {
    // do something with result
}

// but subsequent loops don't
foreach($statement as $result) {
    // never called 
}

有什么方法可以重置语句或寻找第一行吗?

I'm trying to write an iterator for results from a PDO statement but I can't find any way of rewinding to the first row. I would like to avoid the overhead of calling fetchAll and storing all the result data.

// first loop works fine
foreach($statement as $result) {
    // do something with result
}

// but subsequent loops don't
foreach($statement as $result) {
    // never called 
}

Is there some way of reseting the statement or seeking the first row?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

十六岁半 2024-07-16 04:34:38

我很确定这取决于数据库。 因此,您应该尽量避免这种情况。 但是,我认为您可以通过启用缓冲查询来实现您想要的目的。 如果这不起作用,您可以随时使用 获取全部。 这两种解决方案都会影响您的应用程序性能,因此如果结果集很大,请三思。

I'm pretty sure this is database dependent. Because of that, it is something you should try to avoid. However, I think you can achieve what you want by enabling buffered queries. If that doesn't work, you can always pull the result into an array with fetchAll. Both solutions have implications for your applications performance, so think twice about it, if the resultsets are large.

征棹 2024-07-16 04:34:38

我编写的这个小类包装了一个 PDOStatement。 它只存储获取的数据。 如果这不起作用,您可以移动缓存以读取和写入文件。

// Wrap a PDOStatement to iterate through all result rows. Uses a 
// local cache to allow rewinding.
class PDOStatementIterator implements Iterator
{
    public
        $stmt,
        $cache,
        $next;

    public function __construct($stmt)
    {
        $this->cache = array();
        $this->stmt = $stmt;
    }

    public function rewind()
    {
        reset($this->cache);
        $this->next();
    }

    public function valid()
    {
        return (FALSE !== $this->next);
    }

    public function current()
    {
        return $this->next[1];
    }

    public function key()
    {
        return $this->next[0];
    }

    public function next()
    {
        // Try to get the next element in our data cache.
        $this->next = each($this->cache);

        // Past the end of the data cache
        if (FALSE === $this->next)
        {
            // Fetch the next row of data
            $row = $this->stmt->fetch(PDO::FETCH_ASSOC);

            // Fetch successful
            if ($row)
            {
                // Add row to data cache
                $this->cache[] = $row;
            }

            $this->next = each($this->cache);
        }
    }
}

This little class I wrote wraps a PDOStatement. It only stores the data that is fetched. If this doesn't work, you could move the cache to read and write to a file.

// Wrap a PDOStatement to iterate through all result rows. Uses a 
// local cache to allow rewinding.
class PDOStatementIterator implements Iterator
{
    public
        $stmt,
        $cache,
        $next;

    public function __construct($stmt)
    {
        $this->cache = array();
        $this->stmt = $stmt;
    }

    public function rewind()
    {
        reset($this->cache);
        $this->next();
    }

    public function valid()
    {
        return (FALSE !== $this->next);
    }

    public function current()
    {
        return $this->next[1];
    }

    public function key()
    {
        return $this->next[0];
    }

    public function next()
    {
        // Try to get the next element in our data cache.
        $this->next = each($this->cache);

        // Past the end of the data cache
        if (FALSE === $this->next)
        {
            // Fetch the next row of data
            $row = $this->stmt->fetch(PDO::FETCH_ASSOC);

            // Fetch successful
            if ($row)
            {
                // Add row to data cache
                $this->cache[] = $row;
            }

            $this->next = each($this->cache);
        }
    }
}
残月升风 2024-07-16 04:34:38

请参阅此演示文稿中的幻灯片 31,您可以执行 $ statements->rewind()(如果它适用于缓冲查询)。 如果您使用 mysql,则可以使用 PDO_MYSQL_ATTR_USE_BUFFERED_QUERY 来模拟缓冲查询:

$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 1);

@NoahGoodrich 向您指出了 spl。 这是一个始终有效的示例:

$it = new ArrayIterator($stmt->fetchAll());

see slide 31 from this presentation, you can do a $statement->rewind() if it applies to a buffered query. If you use mysql, you can emulate buffered queries by using PDO_MYSQL_ATTR_USE_BUFFERED_QUERY:

$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 1);

@NoahGoodrich pointed you to spl. Here is an example that always works:

$it = new ArrayIterator($stmt->fetchAll());
森林散布 2024-07-16 04:34:38

很久以前就问过,但目前有另一个解决方案。

方法PDOStatement::fetch()可以接收第二个参数,即光标方向,以及PDO::FETCH_ORI_*常量之一。 仅当使用属性 PDO::ATTR_CURSOR 作为 PDO::CURSOR_SCROLL 创建 PDOStatement 时,这些参数才有效。

这样您就可以按如下方式导航。

$sql = "Select * From Tabela";
$statement = $db->prepare($sql, array(
    PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL,
));
$statement->execute();
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_NEXT);  // return next
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_PRIOR); // return previous
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_FIRST); // return first
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_LAST);  // return last
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_ABS, $n); // return to $n position
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_REL, $n); // return to $n position relative to current

更多信息请参阅文档PDO 预定义常量

注意:使用 PDO::FETCH_BOTH 因为这是默认值,只需为您的项目自定义它即可。

Asked a long time ago but currently there's another solution.

The method PDOStatement::fetch() may receives a second parameter, the cursor orientation, with one of PDO::FETCH_ORI_* constants. These parameter are only valid if the PDOStatement are created with the atribute PDO::ATTR_CURSOR as PDO::CURSOR_SCROLL.

This way you can navigate as follows.

$sql = "Select * From Tabela";
$statement = $db->prepare($sql, array(
    PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL,
));
$statement->execute();
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_NEXT);  // return next
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_PRIOR); // return previous
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_FIRST); // return first
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_LAST);  // return last
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_ABS, $n); // return to $n position
$statement->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_REL, $n); // return to $n position relative to current

More info in docs and PDO predefined constants.

Note: used PDO::FETCH_BOTH because is the default, just customize it for your project.

孤星 2024-07-16 04:34:38

您可能想要查看一些可以扩展以提供对对象的类似数组的访问的 PHP SPL 类。

You'll probably want to take a look at some of the PHP SPL classes that can be extended to provide array-like access to objects.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文