#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 байта, вы пробовали использовать length4
bindParam
вместо length10
?2. Также вы пробовали что-то подобное
$pdo->prepare("exec dbo.pIOGetEligSSNDOB ?, ?, ? output")
?
Ответ №1:
мы столкнулись с той же проблемой с SP, предназначенным для возврата 3 выходных параметров из-за побочных эффектов на sql Server через вызов PDO:
не уверен, что это может помочь, но вы можете попробовать префикс вашего вызова процедуры SQL Server с помощью инструкции «SET NOCOUNT ON;» перед съемкой
или начните и завершите процедуру, связанную с транзакцией sql, УСТАНОВИВ ЗНАЧЕНИЕ NOCOUNT НА; … ОТКЛЮЧИТЕ NOCOUNT;
Может работать в вашем случае… или нет, если ваш SP вызывает дополнительные процедуры, где эти флаги установлены неправильно…
Мы все еще ищем лучшее решение…