执行更新查询时获取主键作为输出还是返回?

Posted

技术标签:

【中文标题】执行更新查询时获取主键作为输出还是返回?【英文标题】:Get the primary key as output or return when you performing an Update query? 【发布时间】:2021-05-31 08:57:11 【问题描述】:

我正在尝试获取主键的输出参数,即 ID。当我进行更新查询时,我得到Null。您能建议一种方法吗?

CREATE PROCEDURE sp_InsertTax
    (@ID int output, 
     @TaxAuthorityID int, 
     @TaxClassificationID int, 
     @EntityID int, 
     @AppliesTo_TaxEntityTypeID int)
AS
    IF EXISTS (SELECT * FROM Tax 
               WHERE TaxAuthorityID = @TaxAuthorityID  
                 AND TaxClassificationID = @TaxClassificationID 
                 AND EntityID = @EntityID 
                 AND AppliesTo_TaxEntityTypeID = @AppliesTo_TaxEntityTypeID)
    BEGIN
        UPDATE Tax 
        SET TaxAuthorityID = @TaxAuthorityID, 
            TaxClassificationID = @TaxClassificationID, 
            EntityID = @EntityID, 
            AppliesTo_TaxEntityTypeID = @AppliesTo_TaxEntityTypeID
        WHERE ID = @ID 
    END
    ELSE 
    BEGIN
        IF @ID IS NULL
        BEGIN
            INSERT INTO Tax(TaxAuthorityID, TaxClassificationID, EntityID, AppliesTo_TaxEntityTypeID)
            VALUES (@TaxAuthorityID, @TaxClassificationID, @EntityID, @AppliesTo_TaxEntityTypeID)

            SET @ID = Scope_Identity()
        END
    END
GO

下面是我调用更新存储过程的ADO.NET代码:

public int InsertFederalTax(int ClassificID, int appliesTo)       

    int tax_id = 0;
    Sqlconn.Open();

    SqlCommand cmd = new SqlCommand("sp_InsertTax", Sqlconn);
    cmd.CommandType = CommandType.StoredProcedure;

    var returnparameter = cmd.Parameters.AddWithValue("ID", SqlDbType.Int);
    returnparameter.Direction = ParameterDirection.Output;

    cmd.Parameters.Add("@TaxAuthorityID", SqlDbType.Int).Value = 1;
    cmd.Parameters.Add("@TaxClassificationID", SqlDbType.Int).Value = ClassificID;
    cmd.Parameters.Add("@EntityID", SqlDbType.Int).Value = 0;
    cmd.Parameters.Add("@AppliesTo_TaxEntityTypeID", SqlDbType.Int).Value = appliesTo;

    cmd.ExecuteNonQuery();

    if (!(returnparameter.Value is DBNull))
        tax_id = Convert.ToInt32(returnparameter.Value);
                                 
    Sqlconn.Close();
    return tax_id;

【问题讨论】:

returnparameter 您永远不会将此参数添加到您的 cmd.Parameters 集合中。此外,您使用@ID 作为where 子句的一部分,因此参数方向需要为InputOutput 您不应该使用 SqlDbType 值添加该参数。 @RobertHarvey 将SCOPE_IDENTITY 选择为输出参数完全没问题,无需ExecuteScalarExecuteNonQuery 在这里很好。 还有一个建议,先看看更新,老实说不要担心存在(不存在就不会有更新)。您可以检查@@ROWCOUNT,然后根据需要进行插入。您现在这样做的方式可能导致死锁,因为它会扫描所有行以查找这些 id。如果它确实存在,那么你必须再次找到该行,当你不需要时不要多次旅行。 @Nick_H,请与我们分享操作系统。版本、MSSQL 版本和 .NET Framework 版本。我会生成虚拟机来制作真实的模拟案例。 【参考方案1】:

我认为您打算捕获现有重复记录的 ID,您可以执行以下操作。我还为 SP 添加了最佳实践模板项。另请注意marc_c 的评论关于不要在您的 SP 前加上 sp_

CREATE PROCEDURE InsertTax
(
   @ID int output 
   , @TaxAuthorityID int 
   , @TaxClassificationID int 
   , @EntityID int 
   , @AppliesTo_TaxEntityTypeID int
)
AS
BEGIN
    SET NOCOUNT, XACT_ABORT ON;

    -- This assumes that none of the parameters can ever be null
    -- And from your comments we know that no duplicates can exist
    SELECT @ID = ID
    FROM Tax 
    WHERE TaxAuthorityID = @TaxAuthorityID  
    AND TaxClassificationID = @TaxClassificationID 
    AND EntityID = @EntityID 
    AND AppliesTo_TaxEntityTypeID = @AppliesTo_TaxEntityTypeID;

    IF @ID IS NOT NULL BEGIN
        UPDATE Tax 
        SET TaxAuthorityID = @TaxAuthorityID, 
            TaxClassificationID = @TaxClassificationID, 
            EntityID = @EntityID, 
            AppliesTo_TaxEntityTypeID = @AppliesTo_TaxEntityTypeID
        WHERE ID = @ID;
    END; ELSE BEGIN
        INSERT INTO Tax (TaxAuthorityID, TaxClassificationID, EntityID, AppliesTo_TaxEntityTypeID)
            VALUES (@TaxAuthorityID, @TaxClassificationID, @EntityID, @AppliesTo_TaxEntityTypeID);

        SET @ID = SCOPE_IDENTITY();
    END;

    RETURN 0;
END;
GO

我建议将您的返回参数声明为:

var returnparameter = new SqlParameter("@ID", SqlDbType.Int)

    Direction = ParameterDirection.InputOutput
;

cmd.Parameters.Add(returnparameter);

【讨论】:

我已经按照您的建议进行了尝试。我得到了返回参数。更新查询仍然存在一些问题。 我两次询问操作系统、SQL Server 和 .NET Framework 的版本列表,因为我想设置一个虚拟机来了解并了解更多正在发生的事情,但我没有还没有答案。听起来是不是很奇怪? @AntonioLeonardo 这不是网站的运作方式。也就是说使用任何版本,问题中使用的代码非常通用。 @DaleK,我只想帮助解决这个问题,使用一个场景,而不是任何场景 @DaleK 我正在从 CSV 文件导入数据。如果它们已经存在,如果不插入,我想更新。尽管我的更新查询是正确的,但它仍然会导入重复值。这意味着它不会更新值。【参考方案2】:

请您尝试使用以下更新更改您的 C# 代码,并给我们反馈:

public int InsertFederalTax(int ClassificID, int appliesTo)       

    int tax_id = 0;
    Sqlconn.Open();

    SqlCommand cmd = new SqlCommand("sp_InsertTax", Sqlconn);
    cmd.CommandType = CommandType.StoredProcedure;

    cmd.Parameters.Add("@ID", SqlDbType.Int);  
    cmd.Parameters["@ID"].Direction = ParameterDirection.Output; 

    cmd.Parameters.AddWithValue("@TaxAuthorityID", 1);
    cmd.Parameters.AddWithValue("@TaxClassificationID", ClassificID);
    cmd.Parameters.AddWithValue("@EntityID", 0);
    cmd.Parameters.AddWithValue("@AppliesTo_TaxEntityTypeID", appliesTo);

    cmd.ExecuteNonQuery();

    if(!(cmd.Parameters["@ID"].Value is DBNull))
    
       tax_id = Convert.ToInt32(cmd.Parameters["@ID"].Value);
    
                                 
    Sqlconn.Close();
    return tax_id;

【讨论】:

Nope didn't work Antonio. @Nick_H,拜托,你可以再测试一次吗?我把转换类型错误放在输出变量值上 我已经更改了转换类型,然后我尝试了上述代码。仍然没有工作。谢谢。 @Nick_H,请再次与我们分享操作系统。版本、MSSQL 版本和 .NET Framework 版本。我会生成虚拟机来制作真实的模拟案例。

以上是关于执行更新查询时获取主键作为输出还是返回?的主要内容,如果未能解决你的问题,请参考以下文章

mybatis添加记录时返回主键id

mybatis添加记录时返回主键id

查询没有使用视图索引,而是使用普通表主键索引

[转]mysql大表更新sql的优化策略

关于 主键和外键

返回 Netezza 查询结果