PHP PDO не находит ВЫХОДНОЙ параметр из вызова хранимой процедуры MSSQL

#php #sql-server #pdo #io

#php #sql-сервер #pdo #io

Вопрос:

Работал над этим в течение 3 дней и перепробовал все возможные примеры инструкций, которые я смог найти за эти 3 дня. Я должен попросить помощи в попытке понять, что здесь не работает в отношении выходного параметра. Это межмашинная операция, без взаимодействия с терминалом или веб-страницей и существующая только во внутренней частной подсети. Вызывающий -> Cisco IVR -> PHP -> MSSQL DB -> PHP -> Cisco IVR —> Вызывающий. Я включил весь свой рабочий скрипт PHP, но я хочу сосредоточиться на том, почему мой оператор parameter 3 не работает. Мой код хранимой процедуры MSSQL 1-й.

 ALTER PROCEDURE [dbo].[pIOGetEligSSNDOB]
    
    @SSN NVARCHAR(9),
    @DOB NVARCHAR(8),
    @RCODE INT OUTPUT 
    
AS
BEGIN   

    SELECT * FROM ZASMasterDB.dbo.Eligibility WHERE SSN = @SSN AND DOB = @DOB
    IF @@ROWCOUNT >= 1
    SET @RCODE = 3
    ELSE 
    SET @RCODE = 5
       SELECT 'ReturnCode' = @RCODE
       RETURN @RCODE
       
END


****My working PHP version 7.4.10 script using PDO****


$ID = $_GET['MEMBER_ID']; $DOB = $_GET['DOB'];
$start_time             = microtime(true);

$sth = $pdo->prepare("exec dbo.pIOGetEligSSNDOB ?, ?, ? "); // I am using 2 INPUT and 1 OUTPUT

$RCODE = 0;
$row_count = 0;

$sth->bindParam(1, $ID);     // Members social security number as INPUT to SQL server
$sth->bindParam(2, $DOB);    // Members date of birth as INPUT to SQL server
$sth->bindParam(3, $RCODE, PDO::PARAM_INT|PDO::PARAM_INPUT_OUTPUT,10); //$RCODE to hold the OUTPUT integer 

$sth->execute();
    
$time                   = round( (microtime(true) - $start_time), 4);           
$col_count              = 0;

//ARRAYS TO HELP ORGANIZE THE RESULTS
$column_name_array      = array();
$rows_array             = array();

// THE LOOP!

while($row = $sth->fetch(PDO::FETCH_ASSOC)){
    
    $row_count  ;                         // A MUST for the IVR to know how many records returned 
    $col_count          = count($row);
    $column_name_array  = array_keys($row); 
    $row = array_map('trim',$row);      
    $rows_array[]       = join("·", array_values($row));  //Delineation for the IVR
} 

    $sth = null;       
    $pdo = null;
 
 
?>   


<response>
    <time><?=$time?></time>
    <cols><?=$col_count?></cols>
    <rows><?=$row_count?></rows>
    <code><?=$RCODE?></code>          // This should be the value of the OUTPUT parameter from SQL DB
    <column_names>
    <?=join("·", $column_name_array)?>   
    </column_names>
    <data>
    <?=join("·", $rows_array)?>·                                                     
    </data>
</response>
 

Это результат приведенного выше кода. Это идеально, за исключением отсутствия выходного целого числа от SQL server до $ RCODE, которое затем отображалось бы между элементами кода.

введите описание изображения здесь


Это результат его выполнения в SQL Management Studio

введите описание изображения здесь

Я попробовал, изменил значение int и все равно ничего. Мой PHP не разрешает (? OUPUT) в строке подготовки в качестве 3-й вещи, не нравится? отметьте. Дополнительные исследования здесь показывают, что кто-то говорит, что вам нужно ОБЪЯВЛЕНИЕ. Итак, я сделал свою строку:

  $sth = $pdo->prepare("DECLARE @RCODE INT; exec pIOGetEligSSNDOB ?,?, @RCODE OUTPUT; ");

 

и по-прежнему нет возвращаемого значения, но PHP не жаловался, вернул мои обычные данные. Я попытался использовать то же самое в своей строке подготовки, что и вручную, когда я использую SQL mgt studio.

  $sth = $pdo->prepare("DECLARE @RCODE INT; exec pIOGetEligSSNDOB ?,?, @RCODE = @RCODE OUTPUT;");
 

и нет результата $ RCODE.

Итак, я прочитал обо всем этом «nextRowset», когда я несколько дней назад вытаскивал свои волосы, но потом забыл об этом, все еще пытаясь заставить что-то работать. Спасибо, что напомнил мне, Жоров!!. Поэтому я добавил do к своему исходному while, а затем добавил while в конце всего do, как в тех примерах.

 do {
    while($row = $sth->fetch(PDO::FETCH_ASSOC)){

    $row_count  ;
    $col_count          = count($row);

    $column_name_array  = array_keys($row); 
    
    $row = array_map('trim',$row);      
    
    $rows_array[]       = join("·", array_values($row));
} 
}  while ($sth->nextRowset());  
 

И теперь мой окончательный вывод XML немного отличается, и я вижу целое число 7, но оно было добавлено в конце моих обычных результатов выборки данных, а не туда, куда мне нужно, и это между элементами кода. Затем вместо всех моих обычных имен столбцов, которые обычно отображаются между элементами имени столбца, теперь отображается имя ‘ReturnCode’, которое я не хочу видеть. Итак, у меня определенно возникла проблема с форматированием. Я следовал примерам кода nextRowset точно так, как они объяснены, но почему-то что-то не так с конечным результатом. Это очень сложно, когда вы все еще пытаетесь изучить PHP и не совсем понимаете расположение и синтаксис всего, но сейчас я ближе, чем раньше.

введите описание изображения здесь

Итак, я полагаю, что я решил свой собственный вопрос здесь. Похоже, что «бесплатный драйвер TDS», который я использую для своего кода PHP PDO, не поддерживает использование выходных параметров из MSSQL при первом запуске PHP хранимой процедуры MSSQL, которая возвращает ожидаемый набор результатов. Заметки, которые я нашел для поддержки этого, были прямо здесь, в Stack, но ссылка в этих заметках, объясняющая, почему выходной параметр не поддерживается, говорит, что Microsoft покончила с выходным параметром в MSSQL версии 7 и выше? Я думаю, Ver7 вышел в 1998 году. Я не знаю, так ли это, но я могу заверить вас, что в моей проблеме здесь выходной параметр вообще не будет функционировать. Таким образом, альтернативой было использование команды nextRowset в PHP, но НЕ так, как показано во многих примерах. Я должен был разобраться в этом сам, методом проб и ошибок. Мне не нужен цикл do ..while, и мне не нужно время в конце моего исходного цикла. Пришлось сделать код SQL похожим на это.

 CREATE PROCEDURE [dbo].[pIOGetEligSSDOB]
    
    @SSN nvarchar(10),
    @DOB nvarchar(10)   
    
AS
BEGIN
    DECLARE @RCODE int
    SELECT * FROM ZASMasterDB.dbo.Eligibility WHERE SSN = @SSN AND DOB = @DOB
    IF @@ROWCOUNT >= 1
    SET @RCODE = 7
    ELSE
    SET @RCODE = 8
       SELECT @RCODE      

END
 

Затем в PHP я сохраняю свой первоначальный рабочий цикл точно таким, какой он есть, и я добавил 2 строки после кода цикла. Сначала мне пришлось перейти к следующему набору строк, как показано во всем примере кода, но затем мне нужно перейти в столбец next rows и извлечь однозначный код возврата и поместить его в мой $ rcode, чтобы, наконец, отобразить в моем выводе XML в elements.


 while($row = $sth->fetch(PDO::FETCH_ASSOC)){
    
    $row_count  ;                         
    $col_count          = count($row);
    $column_name_array  = array_keys($row); 
    $row = array_map('trim',$row);      
    $rows_array[]       = join("·", array_values($row));  
} 

   $sth ->nextRowset();
   $rcode = $sth->fetchColumn();

 

Итак, конечный результат выглядит так:

введите описание изображения здесь

Комментарии:

1. Учитывая, что int в SQL Server 32 бита / 4 байта, вы пробовали использовать length 4 bindParam вместо length 10 ?

2. Также вы пробовали что-то подобное $pdo->prepare("exec dbo.pIOGetEligSSNDOB ?, ?, ? output") ?

Ответ №1:

мы столкнулись с той же проблемой с SP, предназначенным для возврата 3 выходных параметров из-за побочных эффектов на sql Server через вызов PDO:

не уверен, что это может помочь, но вы можете попробовать префикс вашего вызова процедуры SQL Server с помощью инструкции «SET NOCOUNT ON;» перед съемкой

или начните и завершите процедуру, связанную с транзакцией sql, УСТАНОВИВ ЗНАЧЕНИЕ NOCOUNT НА; … ОТКЛЮЧИТЕ NOCOUNT;

Может работать в вашем случае… или нет, если ваш SP вызывает дополнительные процедуры, где эти флаги установлены неправильно…

Мы все еще ищем лучшее решение…