Retrieving Multiple Result sets with stored procedure in php/mysqli

后端 未结 3 2000
暗喜
暗喜 2020-11-27 07:05

I have a stored procedure that has multiple result sets. How do I advance to the 2nd result set in mysqli to get those results?

Let\'s say it\'s a stored proc like:<

相关标签:
3条回答
  • 2020-11-27 07:38

    I think you're missing something here (the following has not been tested):

    $stmt = mysqli_prepare($db, 'CALL multiples(?, ?)');
    mysqli_stmt_bind_param($stmt, 'ii', $param1, $param2);
    mysqli_stmt_execute($stmt);
    // fetch the first result set
    $result1 = mysqli_use_result($db);
    // you have to read the result set here 
    while ($row = $result1->fetch_assoc()) {
        printf("%d\n", $row['id']);
    }
    // now we're at the end of our first result set.
    mysqli_free_result($result1);
    
    //move to next result set
    mysqli_next_result($db);
    $result2 = mysqli_use_result($db);
    // you have to read the result set here 
    while ($row = $result2->fetch_assoc()) {
        printf("%d\n", $row['id']);
    }
    // now we're at the end of our second result set.
    mysqli_free_result($result2);
    
    // close statement
    mysqli_stmt_close($stmt);
    

    Using PDO your code would look like:

    $stmt = $db->prepare('CALL multiples(:param1, :param2)');
    $stmt->execute(array(':param1' => $param1, ':param2' => $param2));
    // read first result set
    while ($row = $stmt->fetch()) {
        printf("%d\n", $row['id']);
    }
    $stmt->nextRowset();
    // read second result set
    while ($row = $stmt->fetch()) {
        printf("%d\n", $row['id']);
    }
    

    But I have heard that the PDOStatement::nextRowset() is not implemented with the MySQL PDO driver making it impossible to retrieve multiple result sets:

    • PDO nextRowset not working on MySQL
    • pdo_mysql: stored procedure call returning single rowset blocks future queries
    • Can't use stored procedures from PDO on Windows

    So, depending on your PHP version, you'd have to stick with your mysqli-solution. By the way: do you use the procedural style deliberately? Using object oriented style with mysqli would make your code look a little bit more appealing (my personal opinion).

    0 讨论(0)
  • 2020-11-27 07:39

    This has worked really well for me, it will deal with (as an example) as many Select Lists as there are in your SP. Note how you have to close the $call BEFORE you can then get to the OUT parameters from your SP...

    ?><pre><?
    $call = mysqli_prepare($db, 'CALL test_lists(?, ?, @result)');
    if($call == false) {
        echo "mysqli_prepare (\$db, 'CALL test_lists(?, ?, @result) FAILED!!!\n";
    } else {
        // A couple of example IN parameters for your SP...
        $s_1 = 4;
        $s_2 = "Hello world!";
    
        // Here we go (safer way of avoiding SQL Injections)...
        mysqli_stmt_bind_param($call, 'is', $s_1, $s_2);
    
        // Make the call...
        if(mysqli_stmt_execute($call) == false) {
            echo "mysqli_stmt_execute(\$call) FAILED!!!\n";
        } else {
            //print_r($call);
    
            // Loop until we run out of Recordsets...
            $set = 0;
            while ($recordset = mysqli_stmt_get_result($call)) {
                ++$set;
                //print_r($recordset);
                echo "\nRecordset #" . $set . "...\n";
                if ($recordset->num_rows > 0) {
                    $ctr = 0;
                    while ($row = $recordset->fetch_assoc()) {
                        ++$ctr;
                        //print_r($row);
                        echo "\t" . $ctr . ": ";
                        forEach($row as $key => $val) {
                            echo "[" . $key . "] " . $val . "\t";
                        }
                        echo "\n";
                    }
                }
                echo $recordset->num_rows . " record" . ($recordset->num_rows == 1 ? "" : "s") . ".\n";
                // Clean up, ready for next iteration...
                mysqli_free_result($recordset);
    
                // See if we can get another Recordset...
                mysqli_stmt_next_result($call);
            }
    
            // Then you have to close the $call...
            mysqli_stmt_close($call);
            // ...in order to get to the SP's OUT parameters...
            $select = mysqli_query($db, "SELECT @result");
            $row = mysqli_fetch_row($select);
            $result = $row[0];
            echo "\nOUT @result = " . $result . "\n";
        }
    }
    ?></pre><?
    

    And this is what the output from the above code looks like using my test_lists SP...

    Recordset #1...
        1: [s_1] 4  [user_name] Andrew Foster   
        2: [s_1] 4  [user_name] Cecil   
        3: [s_1] 4  [user_name] Sheff   
    3 records.
    
    Recordset #2...
        1: [s_2] Hello world!   [section_description] The Law   
        2: [s_2] Hello world!   [section_description] History   
        3: [s_2] Hello world!   [section_description] Wisdom Literature 
        4: [s_2] Hello world!   [section_description] The Prophets  
        5: [s_2] Hello world!   [section_description] The Life of Jesus and the Early Church    
        6: [s_2] Hello world!   [section_description] Letters from the Apostle Paul 
        7: [s_2] Hello world!   [section_description] Other Letters from Apostles and Prophets  
        8: [s_2] Hello world!   [section_description] Prophecy - warnings for the present and revelation of the future  
    8 records.
    
    OUT @result = 16
    
    0 讨论(0)
  • 2020-11-27 07:42

    It looks like MySQLi may only support multiple result sets through mysqli_multi_query(), since MySQLi_STMT objects work differently from MySQLi_Result objects.

    PDO seems to be somewhat more abstracted, with the PDOStatement objects being able to handle multiple result sets for both regular queries (PDO::query) and prepared statements(PDO:prepare).

    0 讨论(0)
提交回复
热议问题