2009-11-05 15 views
13

Tengo un procedimiento almacenado que tiene varios conjuntos de resultados. ¿Cómo avanzo al segundo conjunto de resultados en mysqli para obtener esos resultados?Recuperar conjuntos de resultados múltiples con procedimiento almacenado en php/mysqli

Digamos que se trata de un procedimiento almacenado como:

create procedure multiples(param1 INT, param2 INT) 
BEGIN 

SELECT * FROM table1 WHERE id = param1; 

SELECT * FROM table2 WHERE id = param2; 

END $$ 

El PHP es algo como esto:

$stmt = mysqli_prepare($db, 'CALL multiples(?, ?)'); 

mysqli_stmt_bind_param($stmt, 'ii', $param1, $param2); 

mysqli_stmt_execute($stmt); 

mysqli_stmt_bind_result($stmt, $id); 

Entonces esta es la parte que no puedo ir a trabajar. Intenté usar mysqli_next_result para pasar al siguiente conjunto de resultados, pero no puedo hacerlo funcionar. Logramos que funcione con mysqli_store_result y mysqli_fetch_assoc/array/row, pero por alguna razón todos los ints se devuelven como cadenas en blanco.

¿Alguien más se encuentra con esto y tiene una solución?

+0

¿El procedimiento devuelve la llamada correctamente utilizando mysqli_multi_query() en lugar de una instrucción preparada? – gapple

+0

Oh, lo siento. Mi primera respuesta fue no leer tu comentario correctamente. Necesitamos usar declaraciones preparadas, pero la consulta es correcta y funciona para el primer conjunto de resultados. Simplemente no puedo descifrar cómo avanzar al segundo conjunto de resultados. – MacAnthony

Respuesta

13

creo que se está perdiendo algo aquí (la siguiente no ha sido probado):

$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); 

Usando PDO su código se vería así:

$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']); 
} 

Pero he oído que el PDOStatement::nextRowset() no está implementado con el MySQL PDO driver por lo que es imposible recuperar múltiples conjuntos de resultados:

Por lo tanto, dependiendo de la versión de PHP, que tendría que seguir con su solución al mysqli. Por cierto: ¿usas el estilo de procedimiento deliberadamente? El uso de estilo orientado a objetos con mysqli haría que su código se vea un poco más atractivo (mi opinión personal).

+0

Somos conscientes de PDO y aún necesita evaluarlo para ver si es mejor que el mysqli, pero este es un proyecto existente y reemplazar la capa DB no es realista. Mezclar 2 capas de DB es simplemente un mal diseño, IMO. – MacAnthony

+0

Sí, tienes razón, dejé la línea mysqli_stmt_fetch ($ stmt). Un desarrollador anterior usó objetos mysqli-stmt en lugar de objetos del conjunto de resultados. Como se dijo, cuando probamos el conjunto de resultados con fetch_assoc, todas las columnas int se devolvieron como cadenas en blanco. – MacAnthony

+0

Esta es una vieja pregunta y respuesta, pero la solución mysqli ya no funciona ... 'mysqli_use_result' simplemente devolverá' false' después de 'mysqli_stmt_execute' ...' mysqli_use_result' solo se puede usar después de una "consulta" –

1

Parece que MySQLi solo admite varios conjuntos de resultados a través de mysqli_multi_query(), ya que los objetos MySQLi_STMT funcionan de forma diferente a los objetos MySQLi_Result.

DOP parece ser algo más abstracto, con los objetos PDOStatement ser capaz de manejar varios conjuntos de resultados, tanto para consultas regulares (PDO::query) y declaraciones preparadas (PDO:prepare).

+0

también puede iterar sobre múltiples conjuntos de resultados usando '$ stmt-> get_results()' ... '$ stmt-> next_result()' .. ambas funciones/métodos están disponibles solo con "MySQL Native Driver" –

0

Esto me ha funcionado muy bien, tratará (como ejemplo) tantas listas de selección como las hay en su SP. Nótese cómo hay que cerrar la llamada $ ANTES a continuación, puede llegar a los parámetros de salida desde el 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><? 

Y esto es lo que la salida del código anterior se parece a usar mi 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 
Cuestiones relacionadas