如何使用SQL Server、PHP和sqlsrv通过存储过程获得插入行的IDENTITY


How can i get the IDENTITY of an inserted row via stored procedure with SQL Server, PHP and sqlsrv?

信息:

  • PHP 7.0.0
  • SQL Server 2014
  • 使用sqlsrv驱动程序

以下代码可能不是最佳的,但这是PHP:

$nombre = strval($info->nombre);
$idPerfil = 0;
$sqlAltaPerfil = "{CALL AltaPerfil(?,?)}";
$paramsAltaPerfil = [
    [$nombre, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARCHAR(50)],
    [&$idPerfil, SQLSRV_PARAM_INOUT, SQLSRV_PHPTYPE_INT, SQLSRV_SQLTYPE_INT]
];
$stmtAltaPerfil = sqlsrv_query($conexion, $sqlAltaPerfil, $paramsAltaPerfil);
if($stmtAltaPerfil !== false) {
    sqlsrv_next_result($stmtAltaPerfil);
    $sqlAltaPerfilXExComp = "{CALL AltaPerfilXExamenComplementario(?, ?)}";
    foreach($info->arrayIdExComp as $idExComp){
        $idExComp = intval($idExComp);
        var_dump($idExComp);
        $paramsAltaPerfilXExComp = [
            [$idPerfil, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_INT, SQLSRV_SQLTYPE_INT],
            [$idExComp, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_INT, SQLSRV_SQLTYPE_INT]
        ];
        $stmtAltaPerfilXExComp = sqlsrv_query($conexion, $sqlAltaPerfilXExComp, $paramsAltaPerfilXExComp);
        if($stmtAltaPerfilXExComp !== false){
            //bien
        }
        else{
            $exito = false;
            $erroresPhp .= print_r(sqlsrv_errors(), true);
            break;
        }
    }
}

这是SP:

ALTER PROCEDURE [dbo].[AltaPerfil](
    @Descripcion varchar(50),
    @IdPerfil int OUTPUT
) AS
BEGIN
    INSERT INTO PERFILEXAMENCOMPLEMENTARIO (Descripcion) VALUES (@Descripcion)
    SET @IdPerfil = @@IDENTITY
    RETURN
END

我从客户端显示的错误消息中知道$idPerfil保持等于0(第2行(。有趣的是,在SSMS中,SP工作得很好,但当从PHP调用它时,$idPerfil不会修改


编辑:我发现问题不在于代码,而是数据库中的一个触发器由于某种原因干扰了SP中的@@IDENTITY变量。

这就是触发:

ALTER TRIGGER [dbo].[NombresPerfilesUnicos] ON [dbo].[PERFILEXAMENCOMPLEMENTARIO] INSTEAD OF INSERT, UPDATE AS
BEGIN
    DECLARE @NombrePerfil varchar(50)
    SELECT @NombrePerfil = Descripcion FROM inserted
    IF EXISTS(SELECT PEC.IdPerfil FROM PERFILEXAMENCOMPLEMENTARIO PEC WHERE Descripcion = @NombrePerfil)
        PRINT 'ERROR, la descripcion ' + @NombrePerfil + ' ya esta registrada'
    else
        INSERT INTO PERFILEXAMENCOMPLEMENTARIO SELECT Descripcion FROM inserted
END

所以我的新问题是:为什么会发生这种情况?我必须做些什么才能保持这个触发器工作(如有必要进行修改(并使一切正常工作?

尝试使用SCOPE_IDENITY((而不是@@IDENTITY。

来源:http://blog.sqlauthority.com/2007/03/25/sql-server-identity-vs-scope_identity-vs-ident_current-retrieve-last-inserted-identity-of-record/

">选择@@IDENTITY
它返回连接上生成的最后一个IDENTITY值,而不管生成该值的表是什么,也不管生成值的语句的作用域是什么">

">选择SCOPE_IDENITY((
它返回连接和同一范围内的语句生成的最后一个IDENTITY值,而不管生成该值的表是什么">

您可以按以下方式使用:如果存储过程中没有任何与第二个变量相关的事务,则不需要第二个。将IDENT_CURRENT与表名一起使用比其他表名要好得多,因为它只会返回所提到的表的标识值。

--程序部分

ALTER PROCEDURE [dbo].[AltaPerfil](
    @Descripcion VARCHAR(50)
) AS
BEGIN
   INSERT INTO PERFILEXAMENCOMPLEMENTARIO(Description) VALUES (@Descripcion)
    SELECT IDENT_CURRENT('PERFILEXAMENCOMPLEMENTARIO') AS rowID
END

--从PHP调用替换为您的变量,它将返回值为的列rowID

EXEC AltaPerfil 'test'

最后,我所要做的就是将SET NOCOUNT ON添加到SP中,它神奇地起到了的作用

ALTER PROCEDURE [dbo].[AltaPerfil](
    @Descripcion varchar(50),
    @IdPerfil int out
) AS
BEGIN
    SET NOCOUNT ON;
    INSERT INTO PERFILEXAMENCOMPLEMENTARIO (Descripcion) VALUES (@Descripcion)
    SET @IdPerfil = @@IDENTITY
END