如何通过SQL Server,PHP和sqlsrv的存储过程获取插入行的IDENTITY?

时间:2016-09-09 16:05:22

标签: php sql-server

的信息:

  • 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

所以我的新问题是:为什么会这样?我需要做些什么来保持这个触发器工作(必要时修改)并使一切正常工作?

3 个答案:

答案 0 :(得分:3)

尝试使用SCOPE_IDENTITY()而不是@@ Identity。

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

" SELECT @@ IDENTITY
它返回在连接上生成的最后一个IDENTITY值,无论生成该值的表如何,也不管生成该值的语句的范围如何。
"

" SELECT SCOPE_IDENTITY()
它返回在连接上生成的最后一个IDENTITY值以及同一范围内的语句,而不管生成该值的表。
"

答案 1 :(得分:0)

您可以按以下方式使用:如果您在存储过程中没有下一个事务,则不需要第二个变量。使用带有表名的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'

答案 2 :(得分:0)

最后,我所要做的只是将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