как получить несколько наборов результатов из хранимой процедуры mysql в laravel

Я хочу получить несколько наборов результатов из хранимой процедуры в laravel. Есть ли способ сделать это? В настоящее время я могу получить данные одной строки, используя следующий код:

$result = DB::statement('CALL user_login(' . $userId . ',"'
                                                              . $password . '",'
                                                              . '@success'.','
                                                              . '@first_Name'
                                                              );

$res = DB::select('select @success AS success, @first_Name AS firstName);

Here is my stored procedure:

DELIMITER //

DROP PROCEDURE IF EXISTS user_login//

create procedure user_login (IN userid VARCHAR(50),
                                   IN password VARCHAR(50),
                                   out success int,
                                   OUT first_Name VARCHAR(255),
                                   )

begin

declare count int(1);
set count =0;

select firstName, count(*)
into first_Name, count
from `tmc`.user where user_id = userid and pwd=password;

if count >0 then

set success =0;

else 
set success=1;

end if;

end//

person pallavi-Mindfire Solutions    schedule 11.02.2014    source источник


Ответы (2)


Я использую следующий код, и он работает безупречно. Измените его в соответствии с вашими потребностями.

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;
}

Пример вызова:

$params = ['2014-01-01','2014-12-31',100];
$results = APIDB::CallRaw('spGetData',$params);

Результирующий вызов будет:

CALL spGetData(?,?,?)

Если есть только один набор результатов, он будет возвращен как есть. Если их больше, он вернет массив наборов результатов. Ключ использует $pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, true);. Без него будет выброшено ужасное исключение SQLSTATE[HY000]: General error: 2053.

Блок try{} catch() используется для исключения наборов результатов, которые невозможно получить. В частности, у меня есть процедуры, которые возвращают два набора результатов: один в результате обновления (или других операторов выполнения), а последний — в виде реальных данных. Исключение, вызванное fetchAll() с запросом на выполнение, будет PDOException.

Внимание: функция не оптимизирована. Вы можете переписать его одним проходом по параметрам.

person Alex    schedule 20.01.2015

Если ваша хранимая процедура возвращает несколько выходных данных, в этом случае вы можете справиться с этой ситуацией двумя способами.

  1. Перейдите к vendor\laravel\framework\src\Illuminate\Database\Connectors\Connector.php и установите PDO::ATTR_EMULATE_PREPARES как true.

Это создаст проблемы при разработке API, поскольку все API возвращают числа в виде строки, когда ответ возвращается в формате JSON. Например: {"status": "1"}, но должно быть {"status": 1}

  1. Добавить новую связь с конкретной ситуацией. Вы должны решить описанную выше проблему для конкретного API, но не во всех API. Поэтому я предлагаю выбрать вариант 2-й.

Добавьте соединение в config/database.php используйте приведенный ниже код в 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
]) : [],
],

обновите детали в соответствии с вашей конфигурацией.

$procRslts = DB::connection('mysql_procedure')
->select("CALL user_login(?,?,?,?)", array( $userId ,$password,$success,$firstName ));

Я думаю, что в этом вам не нужно передавать последние два параметра, вы можете написать логику int для получения процедуры из базы данных.

Вы можете получить несколько выходных данных, возвращаемых хранимой процедурой.

person er.irfankhan11    schedule 18.02.2020
comment
Пожалуйста, добавьте пояснение к вашему ответу - какие части необходимы для решения проблемы и почему? - person Nico Haase; 18.02.2020
comment
@NicoHaase Спасибо за предложение. Я надеюсь, что теперь это хорошо. - person er.irfankhan11; 19.02.2020