Запрос SQLSRV, возвращающий выходной параметр в виде странного текста

1

У меня есть хранимая процедура в SQL Server 2012, которая сначала проверяет, существуют ли данные, если она делает, то устанавливает параметр Output @Return в 1 и запускает запрос select, а если нет, то устанавливает @Return в 0 и возвращает другой запрос выбора.

При тестировании этой хранимой процедуры, чтобы обеспечить точность данных, она идеально подходит и возвращает данные, которые я ожидаю. Проблема заключается на стороне PHP при попытке прочитать выходной параметр, показывающий t_rrr когда он должен показывать 1 или 0. Я считаю, что проблема может быть в предопределенной константе в sqlsrv_query, но я не могу ее получить за работой. Вот мой код:

PHP:

if(isset($_GET['accno'])) {

$search = $_GET['accno'];

$return = "";

$tsql_callSP = "EXEC Intranet.CustomerSearch @Search=?, @Return=?";
$params = array( 
    array($search, SQLSRV_PARAM_IN),
    array($return, SQLSRV_PARAM_OUT, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR),SQLSRV_SQLTYPE_INT),
    );

/* Execute the query. */
$stmt = sqlsrv_query( $conn, $tsql_callSP, $params);
if( $stmt === false )
{
    echo "EXEC Intranet.CustomerSearch Failed\n";
    die( print_r( sqlsrv_errors(), true));
}

while($res = sqlsrv_next_result($stmt))
{
    // make sure all result sets are stepped through, 
    // since the output params may not be set until this happens
}

echo $return;

if($return == 0) { ?>

   //1st Result Set
   while($row = sqlsrv_fetch_array($stmt)) {
   }

<?php } elseif($return == 1) { // End if Return 0 ?>

   //2nd Result Set
   while($row = sqlsrv_fetch_array($stmt)) {
   }

<?php } // End if Return 1 ?>

Сохраненная процедура SQL:

USE [Intranet]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [Intranet].[CustomerSearch]
    @Search nvarchar(10)
    ,@Return int output
AS
BEGIN
    SET NOCOUNT ON;

    IF EXISTS
        (
            SELECT KeyCode
            FROM Autopart.dbo.Customer
            WHERE KeyCode = @Search
        )
    BEGIN

        SELECT
            Customer.KeyCode
            ,Customer.X13
            ,Customer.Name
            ,Customer.Addra
            ,Customer.Addrb
            ,Customer.Addrc
            ,Customer.Addrd
            ,Customer.Addre
            ,Customer.PCode
            ,Customer.CTitle
            ,Customer.Climit
            ,Customer.Ptype
            ,Customer.Stel
            ,Customer.SCont
            ,Customer.ACont
            ,Customer.XString5
            ,Customer.Locked
            ,Customer.Email
            ,Customer.StopStatus
            ,CusNotes.Comment
        FROM
            Autopart.dbo.Customer
            LEFT OUTER JOIN Autopart.dbo.CusNotes ON Autopart.dbo.Customer.KeyCode = Autopart.dbo.CusNotes.Account
        WHERE
            (Customer.KeyCode = @Search)
            AND (CusNotes.Seqno = 1 OR CusNotes.Seqno IS NULL)

        SET @Return = 1

    END ELSE BEGIN

        SELECT TOP 100
            KeyCode
            ,Name
            ,PCode
            ,Addra
            ,Addrb
            ,Addrc
        FROM
            AUTOPART.dbo.Customer
        WHERE
            (KeyCode LIKE '%'+@Search+'%'
            OR Name LIKE '%'+@Search+'%'
            OR PCode LIKE '%'+@Search+'%')

        SET @Return = 0

    END
END

Я попытался изменить типы PHP и SQL, но не могу получить желаемый результат. Странно, если я создаю хранимую процедуру, которая является оператором INSERT или UPDATE OUTPUT возвращается правильно.

РЕДАКТИРОВАТЬ:

Сортировка хранимых процедур SQL Server - Latin1_General_CI_AS

  • 0
    Попробуйте: $return = 0; вместо $return = ""; и SQLSRV_PARAM_INOUT вместо SQLSRV_PARAM_OUT и SQLSRV_PHPTYPE_INT(SQLSRV_ENC_BINARY) вместо SQLSRV_PHPTYPE_STRING .
  • 0
    Измените переменную $return как предложено, SQLRV_PARAM_INOUT тип параметра на SQLRV_PARAM_INOUT а PHPTYPE - на array($return, SQLSRV_PARAM_INOUT, SQLSRV_PHPTYPE_INT,SQLSRV_SQLTYPE_INT), теперь я всегда возвращаю 0 независимо от запроса (без глупых символов) и mb_detect_encoding ASCII
Теги:
sql-server
stored-procedures
sqlsrv

2 ответа

5
Лучший ответ

У меня был установлен SQL Server и PHP на моем VirtualBox, поэтому я играл.

Немногие вещи:

  • Инициализировать параметры со значением соответствующего типа.
  • Используйте & при прохождении параметров.
  • Прочтите все результаты, возвращаемые хранимой процедурой, используя sqlsrv_next_result. Этот совет берется из sqlsrv_prepare в примере внизу.

Вот код:

$search = "qweryt";
$return = 123;

$tsql_callSP = "EXEC Intranet.CustomerSearch @Search=?, @Return=?";
$params = array( 
    array(&$search, SQLSRV_PARAM_IN),
    array(&$return, SQLSRV_PARAM_OUT),
    );

$stmt = sqlsrv_query($conn, $tsql_callSP, $params);
if ($stmt === false)
{
    echo "EXEC Intranet.CustomerSearch Failed\n";
    die( print_r( sqlsrv_errors(), true));
}
else
{
    while($res = sqlsrv_next_result($stmt))
    {
        // make sure all result sets are stepped through, 
        // since the output params may not be set until this happens
    }
}

echo $return;

Проверено с помощью PHP 5.4.28, SQL Server Express 2014, Microsoft для PHP SQLSRV 3.2

Когда у вас есть хранимая процедура, которая выполняет только INSERT или UPDATE, т.е. не возвращает результат SELECT, тогда sqlsrv_next_result не требуется для получения значений output параметров. Если есть SELECT вместе с выходными параметрами, это фактически означает, что процедура возвращает несколько наборов результатов, и вам нужно их прочитать.

Собственно, здесь очень похожий вопрос.

редактировать

Если я правильно понял вас, вы хотите сначала получить значение параметра OUTPUT. Затем вы хотите получить результат SELECT.

Насколько я понимаю, это невозможно. SQL Server возвращает результат SELECT в первом результирующем наборе, который вы можете прочитать с помощью sqlsrv_fetch_array. Затем вы переходите во второй результирующий набор, используя sqlsrv_next_result. В этот момент значение параметра OUTPUT переносится в вашу переменную PHP, поскольку SQL Server отправляет значения параметров OUTPUT в последний набор результатов. После вызова sqlsrv_next_result первый набор результатов больше не доступен, когда вы выполняете sqlsrv_fetch_array.

Кстати, когда вы сказали

Странно, если я создаю хранимую процедуру, которая является оператором INSERT или UPDATE, OUTPUT возвращается правильно.

это имеет смысл. Когда хранимая процедура не имеет SELECT и имеет значение SET NOCOUNT ON; , то единственным возвращаемым результатом является параметр OUTPUT, поэтому ваша переменная PHP назначается с правильным значением без явных вызовов sqlsrv_next_result.

Итак, у вас есть как минимум два варианта.

1) Прочитайте полный результат SELECT во временном массиве, используя sqlsrv_fetch_array. Затем используйте sqlsrv_next_result чтобы получить значение параметра OUTPUT. Затем обработайте результат первого SELECT сохраненного в вашем массиве, на основе полученного значения параметра OUTPUT.

2) Не используйте параметр OUTPUT. С такими параметрами SQL Server возвращает несколько наборов результатов неявно. Так как у вас есть несколько результирующих множеств, возвратите два набора результатов явно. В вашей хранимой процедуре сначала сделайте SELECT который возвращает только одну строку с одним номером, тогда ваш основной SELECT:

ALTER PROCEDURE [Intranet].[CustomerSearch]
    @Search nvarchar(10)
AS
BEGIN
    SET NOCOUNT ON;

    IF EXISTS
        (
            SELECT KeyCode
            FROM Autopart.dbo.Customer
            WHERE KeyCode = @Search
        )
    BEGIN
        SELECT CAST(1 AS int) AS ReturnCode;

        SELECT
            Customer.KeyCode
            ,Customer.X13
            ,Customer.Name
            ,Customer.Addra
            ,Customer.Addrb
            ,Customer.Addrc
            ,Customer.Addrd
            ,Customer.Addre
            ,Customer.PCode
            ,Customer.CTitle
            ,Customer.Climit
            ,Customer.Ptype
            ,Customer.Stel
            ,Customer.SCont
            ,Customer.ACont
            ,Customer.XString5
            ,Customer.Locked
            ,Customer.Email
            ,Customer.StopStatus
            ,CusNotes.Comment
        FROM
            Autopart.dbo.Customer
            LEFT OUTER JOIN Autopart.dbo.CusNotes ON Autopart.dbo.Customer.KeyCode = Autopart.dbo.CusNotes.Account
        WHERE
            (Customer.KeyCode = @Search)
            AND (CusNotes.Seqno = 1 OR CusNotes.Seqno IS NULL)
        ;

    END ELSE BEGIN

        SELECT CAST(0 AS int) AS ReturnCode;

        SELECT TOP 100
            KeyCode
            ,Name
            ,PCode
            ,Addra
            ,Addrb
            ,Addrc
        FROM
            AUTOPART.dbo.Customer
        WHERE
            KeyCode LIKE '%'+@Search+'%'
            OR Name LIKE '%'+@Search+'%'
            OR PCode LIKE '%'+@Search+'%'
        ;
    END
END

В PHP код вызовите sqlsrv_fetch_array первый раз, чтобы прочитать ReturnCode. Затем вызовите sqlsrv_next_result чтобы переключиться на второй результирующий набор. Затем вызовите sqlsrv_fetch_array чтобы прочитать результат основного SELECT.

$search = "qweryt";

$tsql_callSP = "EXEC Intranet.CustomerSearch @ParamSearch=?";
$params = array
    (
    array(&$search, SQLSRV_PARAM_IN)
    );

$stmt = sqlsrv_query($conn, $tsql_callSP, $params);
if( $stmt === false )
{
    echo "EXEC Failed\n";
    die( print_r( sqlsrv_errors(), true));
}

echo "First result set:\n";
while ($row = sqlsrv_fetch_array($stmt))
{
    var_dump($row);
}

echo "Next result:\n";
$next_res = sqlsrv_next_result($stmt);
var_dump($next_res);

echo "Second result set:\n";
while ($row = sqlsrv_fetch_array($stmt))
{
    var_dump($row);
}
  • 0
    Большое спасибо за ваши исследования и помощь, тег $return теперь корректно возвращается как 1 или 0, как и ожидалось. Я заметил, что забыл упомянуть кое-что важное, что я добавил к своему вопросу, когда проверка возврата вернется, она будет выполняться, while($row = sqlsrv_fetch_array($stmt)) { зависимости от результата возврата
  • 0
    Извините, я не совсем понимаю. Получаете ли вы правильные результаты сейчас или все еще есть проблема?
Показать ещё 5 комментариев
0

Это связано с проблемой кодирования символов с выходом PHP. Попробуйте использовать

header ('Content-type: text/html; charset=UTF-8');

или

header ('Content-type: text/html; charset=ISO-8859-1');

Кроме того, вы можете проверить эту хорошую статью.

  • 0
    Я попробовал оба этих заголовка, как вы предлагаете, и символы меняются следующим образом. UTF-8 - 0 + �� +. ISO-8859-1 - 0ÄÄ. Я также попытался изменить PHPTYPE на SQLSRV_PHPTYPE_INT
  • 0
    Сортировка хранимой процедуры: Latin1_General_CI_AS, если это имеет какое-либо значение?
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню