Los procedimientos almacenados

La base de datos MySQL soporta los procedimientos almacenados. Un procedimiento almacenado es una subrutina almacenada en el catálogo de la base de datos. Las aplicaciones pueden llamar y ejecutar un procedimiento almacenado. La consulta SQL CALL es utilizada para ejecutar un procedimiento almacenado.

Parámetro

Los procedimientos almacenados pueden tener parámetros IN, INOUT y OUT, dependiendo de la versión de MySQL. La interfaz mysqli no tiene una noción específica de los diferentes tipos de parámetros.

Parámetro IN

Los parámetros de entrada son proporcionados con la consulta CALL. Asegúrese de escapar correctamente los valores.

Ejemplo #1 Llamada a un procedimiento almacenado

<?php

mysqli_report
(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("example.com", "user", "password", "database");

$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT)");

$mysqli->query("DROP PROCEDURE IF EXISTS p");
$mysqli->query("CREATE PROCEDURE p(IN id_val INT) BEGIN INSERT INTO test(id) VALUES(id_val); END;");

$mysqli->query("CALL p(1)");

$result = $mysqli->query("SELECT id FROM test");

var_dump($result->fetch_assoc());

El resultado del ejemplo sería:

array(1) {
  ["id"]=>
  string(1) "1"
}

Parámetro INOUT/OUT

Los valores de los parámetros INOUT/OUT son accedidos utilizando las variables de sesión.

Ejemplo #2 Uso de las variables de sesión

<?php

mysqli_report
(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("example.com", "user", "password", "database");

$mysqli->query("DROP PROCEDURE IF EXISTS p");
$mysqli->query('CREATE PROCEDURE p(OUT msg VARCHAR(50)) BEGIN SELECT "Hi!" INTO msg; END;');

$mysqli->query("SET @msg = ''");
$mysqli->query("CALL p(@msg)");

$result = $mysqli->query("SELECT @msg as _p_out");

$row = $result->fetch_assoc();
echo
$row['_p_out'];

El resultado del ejemplo sería:

Hi!

Los desarrolladores de aplicaciones y de frameworks pueden proporcionar una API más amigable utilizando una mezcla de las variables de sesión y una inspección del catálogo de la base de datos. Sin embargo, tenga en cuenta el impacto en el rendimiento debido a una solución personalizada basada en la inspección del catálogo.

Gestión de los juegos de resultados

Los procedimientos almacenados pueden devolver juegos de resultados. Los juegos de resultados devueltos desde un procedimiento almacenado no pueden ser recuperados correctamente utilizando la función mysqli::query(). La función mysqli::query() combina la ejecución de la consulta y la recuperación del primer juego de resultados en un juego de resultados en memoria tamponada, si lo hay. Sin embargo, existen otros juegos de resultados provenientes del procedimiento almacenado que están ocultos al usuario y que hacen que la función mysqli::query() falle al recuperar los juegos de resultados esperados por el usuario.

Los juegos de resultados devueltos desde un procedimiento almacenado son recuperados utilizando la función mysqli::real_query() o mysqli::multi_query(). Estas dos funciones permiten la recuperación de cualquier número de juegos de resultados devueltos por una consulta, como la consulta CALL. Fallar en la recuperación de todos los juegos de resultados devueltos por un procedimiento almacenado causa un error.

Ejemplo #3 Recuperación de los resultados provenientes de un procedimiento almacenado

<?php

mysqli_report
(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("example.com", "user", "password", "database");

$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT)");
$mysqli->query("INSERT INTO test(id) VALUES (1), (2), (3)");

$mysqli->query("DROP PROCEDURE IF EXISTS p");
$mysqli->query('CREATE PROCEDURE p() READS SQL DATA BEGIN SELECT id FROM test; SELECT id + 1 FROM test; END;');

$mysqli->multi_query("CALL p()");

do {
if (
$res = $mysqli->store_result()) {
var_dump($result->fetch_all());
$result->free();
}
} while (
$mysqli->next_result());

El resultado del ejemplo sería:

---
array(3) {
  [0]=>
  array(1) {
    [0]=>
    string(1) "1"
  }
  [1]=>
  array(1) {
    [0]=>
    string(1) "2"
  }
  [2]=>
  array(1) {
    [0]=>
    string(1) "3"
  }
}
---
array(3) {
  [0]=>
  array(1) {
    [0]=>
    string(1) "2"
  }
  [1]=>
  array(1) {
    [0]=>
    string(1) "3"
  }
  [2]=>
  array(1) {
    [0]=>
    string(1) "4"
  }
}

Uso de las consultas preparadas

No se requiere una gestión especial al utilizar la interfaz de preparación de consultas para recuperar los resultados desde el mismo procedimiento almacenado que el anterior. Las interfaces de consulta preparada y no preparada son similares. Tenga en cuenta que todas las versiones del servidor MySQL no soportan la preparación de las consultas SQL CALL.

Ejemplo #4 Procedimientos almacenados y consulta preparada

<?php

mysqli_report
(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("example.com", "user", "password", "database");
if (
$mysqli->connect_errno) {
echo
"Fallo durante la conexión a MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
}

$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT)");
$mysqli->query("INSERT INTO test(id) VALUES (1), (2), (3)");

$mysqli->query("DROP PROCEDURE IF EXISTS p");
$mysqli->query('CREATE PROCEDURE p() READS SQL DATA BEGIN SELECT id FROM test; SELECT id + 1 FROM test; END;');

$stmt = $mysqli->prepare("CALL p()");

if (!
$stmt->execute()) {
echo
"Fallo durante la ejecución: (" . $stmt->errno . ") " . $stmt->error;
}

do {
if (
$result = $stmt->get_result()) {
var_dump($result->fetch_all());
$result->free();
}
} while (
$stmt->next_results());

El resultado del ejemplo sería:

---
array(3) {
  [0]=>
  array(1) {
    [0]=>
    int(1)
  }
  [1]=>
  array(1) {
    [0]=>
    int(2)
  }
  [2]=>
  array(1) {
    [0]=>
    int(3)
  }
}
---
array(3) {
  [0]=>
  array(1) {
    [0]=>
    int(2)
  }
  [1]=>
  array(1) {
    [0]=>
    int(3)
  }
  [2]=>
  array(1) {
    [0]=>
    int(4)
  }
}

Por supuesto, el uso de la API de enlace para la recuperación también es soportado.

Ejemplo #5 Procedimientos almacenados y consulta preparada utilizando la API de enlace

<?php

mysqli_report
(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("example.com", "user", "password", "database");

$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT)");
$mysqli->query("INSERT INTO test(id) VALUES (1), (2), (3)");

$mysqli->query("DROP PROCEDURE IF EXISTS p");
$mysqli->query('CREATE PROCEDURE p() READS SQL DATA BEGIN SELECT id FROM test; SELECT id + 1 FROM test; END;');

$stmt = $mysqli->prepare("CALL p()");

$stmt->execute();

do {
if (
$stmt->store_result()) {
$stmt->bind_result($id_out);
while (
$stmt->fetch()) {
echo
"id = $id_out\n";
}
}
} while (
$stmt->next_result());

El resultado del ejemplo sería:

id = 1
id = 2
id = 3
id = 2
id = 3
id = 4

Ver también

add a note

User Contributed Notes 1 note

up
2
Valverde
5 years ago
<?php

// Store procedure call without params

$MyConnection = new mysqli ("DB_SERVER", "DB_USER", "DB_PASS", "DB_NAME");

mysqli_multi_query ($MyConnection, "CALL MyStoreProcedure") OR DIE (mysqli_error($MyConnection));

while (
mysqli_more_results($MyConnection)) {

if (
$result = mysqli_store_result($MyConnection)) {

while (
$row = mysqli_fetch_assoc($result)) {

// i.e.: DBTableFieldName="userID"
echo "row = ".$row["DBTableFieldName"]."<br />";
....

}
mysqli_free_result($result);
}
mysqli_next_result($conn);

}
?>
*******************************************************************
<?php

// Store procedure call using params

$MyConnection = new mysqli ("DB_SERVER", "DB_USER", "DB_PASS", "DB_NAME");

mysqli_query($MyConnection ,"SET @p0='".$MyParam1."'");
mysqli_query($MyConnection ,"SET @p1='".$MyParam2."'");
mysqli_multi_query ($MyConnection, "CALL MyStoreProcedure (@p0,@p1)") OR DIE (mysqli_error($MyConnection));

while (
mysqli_more_results($MyConnection)) {

if (
$result = mysqli_store_result($MyConnection)) {

while (
$row = mysqli_fetch_assoc($result)) {

// i.e.: DBTableFieldName="userID"
echo "row = ".$row["DBTableFieldName"]."<br />";
....

}
mysqli_free_result($result);
}
mysqli_next_result($conn);

}
?>
To Top