SQLSRV查询将输出参数作为奇怪文本返回

时间:2015-05-18 10:10:12

标签: php sql sql-server stored-procedures sqlsrv

我在SQL Server 2012中有一个存储过程,首先检查数据是否存在,如果存在,则将Output参数@Return设置为1并运行select查询,如果不存在,则设置@Return为0并返回不同的选择查询。

在测试此存储过程以确保数据准确时,它是完美的并返回我期望的数据。问题在于PHP端在尝试读取它显示{1}时显示{1}的输出参数时,它应该显示为1或0.我相信问题可能在sqlsrv_query中的预定义常量但我似乎无法让它工作。这是我的代码:

PHP:

��t_rrr

SQL存储过程:

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 ?>

我尝试过更改PHP和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 INSERT语句的存储过程,UPDATE会正确返回。

修改

SQL Server存储过程排序规则是Latin1_General_CI_AS

2 个答案:

答案 0 :(得分:5)

我碰巧在我的VirtualBox上安装了SQL Server和PHP,所以我玩了。

少数事情:

  • 使用正确类型的值初始化参数。
  • 传递参​​数时使用&
  • 使用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,PHP SQLSRV 3.2的Microsoft驱动程序验证

当您的存储过程仅INSERTUPDATE时,即没有返回SELECT的结果时,则不需要sqlsrv_next_result获取output参数的值。如果SELECT与输出参数一起使用,则实际上意味着该过程返回多个结果集,您需要阅读所有这些结果集。

实际上,这是一个非常similar question

修改

如果我理解正确,您需要先检索OUTPUT参数的值。然后,您想要检索SELECT语句的结果。

据我了解,这是不可能的。 SQL Server在第一个结果集中返回SELECT语句的结果,您可以使用sqlsrv_fetch_array读取该结果。然后使用sqlsrv_next_result移动到第二个结果集。此时,OUTPUT参数的值将传输到PHP变量,因为SQL Server在最后一个结果集中发送OUTPUT个参数的值。致电sqlsrv_next_result后,当您执行sqlsrv_fetch_array时,第一个结果集将不再可用。

顺便说一下,当你说

  

奇怪的是,如果我创建一个INSERT或的存储过程   OUTPUT正确返回的UPDATE语句。

,这很有道理。当存储过程没有SELECT语句并且它有SET NOCOUNT ON;时,返回的唯一结果集是OUTPUT个参数,因此您的PHP变量被赋值为正确的值而没有显式调用sqlsrv_next_result

所以,你至少有两个选择。

1)使用SELECTsqlsrv_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);
}

答案 1 :(得分:0)

这是由于PHP输出的字符编码问题。尝试使用

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

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

另外,您可以查看this nice article.