I want to fetch multiple result sets from a stored procedure in laravel. Is there a way I can do this? Currently, I can get a single row\'s data using the below code:
<I am using the following code and it works flawlessly. Change it to suit your needs.
public static function CallRaw($procName, $parameters = null, $isExecute = false)
{
$syntax = '';
for ($i = 0; $i < count($parameters); $i++) {
$syntax .= (!empty($syntax) ? ',' : '') . '?';
}
$syntax = 'CALL ' . $procName . '(' . $syntax . ');';
$pdo = DB::connection()->getPdo();
$pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, true);
$stmt = $pdo->prepare($syntax,[\PDO::ATTR_CURSOR=>\PDO::CURSOR_SCROLL]);
for ($i = 0; $i < count($parameters); $i++) {
$stmt->bindValue((1 + $i), $parameters[$i]);
}
$exec = $stmt->execute();
if (!$exec) return $pdo->errorInfo();
if ($isExecute) return $exec;
$results = [];
do {
try {
$results[] = $stmt->fetchAll(\PDO::FETCH_OBJ);
} catch (\Exception $ex) {
}
} while ($stmt->nextRowset());
if (1 === count($results)) return $results[0];
return $results;
}
Example call:
$params = ['2014-01-01','2014-12-31',100];
$results = APIDB::CallRaw('spGetData',$params);
The resulting call will be:
CALL spGetData(?,?,?)
If there is only one resultset, it will be returned as is. If there are more, it will return an array of result sets. The key is using $pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, true);
. Without it, a horrible SQLSTATE[HY000]: General error: 2053
exception will be thrown.
The try{} catch() block is used to eliminate the resultsets that cannot be fetched. Particularly, I have procedures that returns two resultsets, one as a result of an update (or other execute statements) and the last one as the real data. The exception thrown on fetchAll()
with an execute query will be PDOException
.
Warning: the function is not optimised. You can rewrite it with one single pass through the parameters.
If your stored procedure returns multiple outputs, In this case, you can handle this situation by two methods.
vendor\laravel\framework\src\Illuminate\Database\Connectors\Connector.php
and set PDO::ATTR_EMULATE_PREPARES
as true
.It will create problems when you will developing APIs, because of all APIs return numbers as a string when response return in JSON Like: {"status": "1"}
but it should be {"status": 1}
Add connection in the config/database.php
use below code into connections
'mysql_procedure' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => 'sv_',
'prefix_indexes' => true,
'strict' => false,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),PDO::ATTR_EMULATE_PREPARES => true
]) : [],
],
update details as per your configuration.
$procRslts = DB::connection('mysql_procedure')
->select("CALL user_login(?,?,?,?)", array( $userId ,$password,$success,$firstName ));
I think in this you don't need to pass the last two parameters, you can write logic int procedure to get from the database.
You can get multiple outputs returned by the stored procedure.