ZetCode

PHP PDOStatement::nextRowset 方法

最后修改于 2025 年 4 月 19 日

PDOStatement::nextRowset 方法允许处理来自存储过程或批处理查询的多个结果集。它会前进到下一个结果集。

基本定义

当一个语句返回多个结果集时,PDOStatement::nextRowset 将游标移动到下一个结果集。这在存储过程调用中很常见。

语法:public PDOStatement::nextRowset(): bool。成功时返回 true,如果没有更多结果集则返回 false。失败时抛出 PDOException。

简单的 nextRowset 示例

此示例演示了 nextRowset 与存储过程的基本用法。

nextrowset_basic.php
<?php

declare(strict_types=1);

try {
    $pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    $stmt = $pdo->query("CALL get_multiple_results()");
    
    // Process first result set
    while ($row = $stmt->fetch()) {
        echo "User: {$row['name']}\n";
    }
    
    // Move to next result set
    if ($stmt->nextRowset()) {
        while ($row = $stmt->fetch()) {
            echo "Product: {$row['product_name']}\n";
        }
    }
} catch (PDOException $e) {
    echo "Error: " . $e->getMessage();
}

此代码调用一个返回两个结果集的存储过程。我们处理第一个结果集,然后使用 nextRowset 访问第二个结果集。请务必检查 nextRowset 的返回值。

处理多个结果集

此示例展示了如何处理查询中数量不确定的结果集。

nextrowset_multiple.php
<?php

declare(strict_types=1);

try {
    $pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    $stmt = $pdo->query("SELECT * FROM users; SELECT * FROM products;");
    
    $resultSetNumber = 1;
    do {
        echo "Result Set #$resultSetNumber:\n";
        while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
            print_r($row);
        }
        echo "\n";
        $resultSetNumber++;
    } while ($stmt->nextRowset());
} catch (PDOException $e) {
    echo "Error: " . $e->getMessage();
}

此代码在一个查询中执行两个 SELECT 语句。do-while 循环处理每个结果集,直到 nextRowset 返回 false。每次迭代处理一个结果集。

组合 INSERT 和 SELECT

此示例展示了如何将 nextRowset 与组合的 INSERT 和 SELECT 查询一起使用。

nextrowset_insert_select.php
<?php

declare(strict_types=1);

try {
    $pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    $stmt = $pdo->query("
        INSERT INTO logs (message) VALUES ('Test log entry');
        SELECT * FROM logs ORDER BY created_at DESC LIMIT 5;
    ");
    
    echo "Insert completed\n";
    
    if ($stmt->nextRowset()) {
        echo "Recent log entries:\n";
        while ($row = $stmt->fetch()) {
            echo "{$row['created_at']}: {$row['message']}\n";
        }
    }
} catch (PDOException $e) {
    echo "Error: " . $e->getMessage();
}

此代码执行一个 INSERT,然后执行一个 SELECT。INSERT 不返回行,因此我们使用 nextRowset 跳转到 SELECT 结果集。这种模式对于审计日志记录非常有用。

带输出参数的存储过程

此示例演示了 nextRowset 与带输出参数的存储过程的用法。

nextrowset_output_params.php
<?php

declare(strict_types=1);

try {
    $pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    $stmt = $pdo->prepare("CALL get_user_stats(?, @total_users, @avg_age)");
    $stmt->execute(['active']);
    
    // First result set - user data
    while ($row = $stmt->fetch()) {
        echo "User: {$row['name']}, Age: {$row['age']}\n";
    }
    
    // Move to next result set - output parameters
    if ($stmt->nextRowset()) {
        $output = $pdo->query("SELECT @total_users AS total_users, @avg_age AS avg_age")->fetch();
        echo "Total users: {$output['total_users']}\n";
        echo "Average age: {$output['avg_age']}\n";
    }
} catch (PDOException $e) {
    echo "Error: " . $e->getMessage();
}

此代码调用一个首先返回用户数据,然后返回输出参数的存储过程。我们处理用户数据,然后在使用输出参数之前使用 nextRowset。输出参数在过程调用后需要单独查询。

nextRowset 的错误处理

此示例展示了处理多个结果集时的正确错误处理方法。

nextrowset_error_handling.php
<?php

declare(strict_types=1);

try {
    $pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    $stmt = $pdo->query("
        SELECT * FROM valid_table;
        SELECT * FROM non_existent_table;
    ");
    
    // Process first result set
    echo "First result set:\n";
    while ($row = $stmt->fetch()) {
        print_r($row);
    }
    
    // Attempt to move to next result set
    try {
        if (!$stmt->nextRowset()) {
            echo "No more result sets\n";
        } else {
            echo "Second result set:\n";
            while ($row = $stmt->fetch()) {
                print_r($row);
            }
        }
    } catch (PDOException $e) {
        echo "Error moving to next result set: " . $e->getMessage();
    }
} catch (PDOException $e) {
    echo "Query error: " . $e->getMessage();
}

此代码展示了用于处理错误的嵌套 try-catch 块。第二个查询失败了,但我们捕获了来自 nextRowset 的异常。在处理不可信查询时,始终将 nextRowset 调用包装在 try-catch 中。

SQL Server 多个结果集

此示例演示了 nextRowset 与 SQL Server 的多个结果集用法。

nextrowset_sqlserver.php
<?php

declare(strict_types=1);

try {
    $pdo = new PDO('sqlsrv:Server=localhost;Database=testdb', 'user', 'password');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    $stmt = $pdo->query("
        SELECT * FROM customers WHERE region = 'North';
        SELECT * FROM orders WHERE order_date > '2023-01-01';
        SELECT COUNT(*) AS product_count FROM products;
    ");
    
    $resultNumber = 1;
    do {
        echo "Result Set #$resultNumber:\n";
        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
        print_r($rows);
        $resultNumber++;
    } while ($stmt->nextRowset());
} catch (PDOException $e) {
    echo "Error: " . $e->getMessage();
}

SQL Server 经常返回多个结果集。此代码执行三个查询并处理所有结果。fetchAll 用于检索每个结果集的所有行。循环继续,直到 nextRowset 返回 false。

将 nextRowset 与 Column Count 结合使用

此示例展示了如何将 columnCount 与 nextRowset 一起使用来处理动态结果。

nextrowset_column_count.php
<?php

declare(strict_types=1);

try {
    $pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    $stmt = $pdo->query("
        SELECT id, name FROM users LIMIT 2;
        SELECT product_id, product_name, price FROM products LIMIT 3;
    ");
    
    $setNumber = 1;
    do {
        $colCount = $stmt->columnCount();
        echo "Result Set #$setNumber ($colCount columns):\n";
        
        if ($colCount > 0) {
            while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
                print_r($row);
            }
        } else {
            echo "No columns in this result set\n";
        }
        
        $setNumber++;
    } while ($stmt->nextRowset());
} catch (PDOException $e) {
    echo "Error: " . $e->getMessage();
}

此代码在处理每个结果集之前检查 columnCount。某些结果集可能没有列(例如 INSERT 语句之后)。该示例在批处理中处理了返回数据和不返回数据的查询。

最佳实践

来源

PHP nextRowset 文档

本教程涵盖了 PDOStatement::nextRowset 方法,并通过实际示例展示了不同的数据库场景和正确的错误处理。

作者

我的名字是 Jan Bodnar,我是一位充满激情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出 所有 PHP PDO 函数