【问题标题】:SQL Server stored procedure Nullable parameterSQL Server 存储过程 Nullable 参数
【发布时间】:2014-02-20 20:44:32
【问题描述】:

问题
当将值提供给以下脚本然后使用 C# 中的设置(或在 SQL Server 环境中)执行时,这些值不会在数据库中更新。

存储过程:

-- Updates the Value of any type of PropertyValue
-- (Type meaining simple Value, UnitValue, or DropDown)
CREATE PROCEDURE [dbo].[usp_UpdatePropertyValue]
    @PropertyValueID int,
    @Value varchar(max) = NULL,
    @UnitValue float = NULL,
    @UnitOfMeasureID int = NULL,
    @DropDownOptionID int = NULL
AS
BEGIN   
    -- If the Property has a @Value, Update it.
    IF @Value IS NOT NULL
    BEGIN
        UPDATE [dbo].[PropertyValue]
        SET
            Value = @Value
        WHERE
            [dbo].[PropertyValue].[ID] = @PropertyValueID
    END
    -- Else check if it has a @UnitValue & UnitOfMeasureID
    ELSE IF @UnitValue IS NOT NULL AND @UnitOfMeasureID IS NOT NULL
    BEGIN
        UPDATE [dbo].[UnitValue]
        SET
            UnitValue = @UnitValue,
            UnitOfMeasureID = @UnitOfMeasureID
        WHERE
            [dbo].[UnitValue].[PropertyValueID] = @PropertyValueID          
    END
    -- Else check if it has just a @UnitValue
    ELSE IF @UnitValue IS NOT NULL AND @UnitOfMeasureID IS NULL
    BEGIN
        UPDATE [dbo].[UnitValue]
        SET
            UnitValue = @UnitValue
        WHERE
            [dbo].[UnitValue].[PropertyValueID] = @PropertyValueID  
    END
    -- Else check if it has a @DropDownSelection to update.
    ELSE IF @DropDownOptionID IS NULL
    BEGIN
        UPDATE [dbo].[DropDownSelection]
        SET
            SelectedOptionID = @DropDownOptionID
        WHERE
            [dbo].[DropDownSelection].[PropertyValueID] = @PropertyValueID
    END
END

当我执行这个脚本时,如下所示,它不会更新任何值。

示例执行:

String QueryString = "EXEC [dbo].[usp_UpdatePropertyValue] @PropertyValueID, @Value, @UnitValue, @UnitOfMeasureID, @DropDownOptionID";
SqlCommand Cmd = new SqlCommand(QueryString, this._DbConn);

Cmd.Parameters.Add(new SqlParameter("@PropertyValueID", System.Data.SqlDbType.Int));
Cmd.Parameters.Add(new SqlParameter("@Value", System.Data.SqlDbType.Int));
Cmd.Parameters.Add(new SqlParameter("@UnitValue", System.Data.SqlDbType.Int));
Cmd.Parameters.Add(new SqlParameter("@UnitOfMeasureID", System.Data.SqlDbType.Int));
Cmd.Parameters.Add(new SqlParameter("@DropDownOptionID", System.Data.SqlDbType.Int));

Cmd.Parameters["@PropertyValueID"].Value = Property.Value.ID; // 1
Cmd.Parameters["@Value"].IsNullable = true;
Cmd.Parameters["@Value"].Value = DBNull.Value;
Cmd.Parameters["@UnitValue"].IsNullable = true;
Cmd.Parameters["@UnitValue"].Value = DBNull.Value;
Cmd.Parameters["@UnitOfMeasureID"].IsNullable = true;
Cmd.Parameters["@UnitOfMeasureID"].Value = DBNull.Value;
Cmd.Parameters["@DropDownOptionID"].IsNullable = true;
Cmd.Parameters["@DropDownOptionID"].Value = 2; // Current Value in DB: 3

详情:

运行执行后(通过 C# 代码或 SQL Server 环境)它不会更新 dbo.DropDownSelection.SelectedOptionID。我猜这可能是因为dbo.DropDownSelection.SelectedOptionID 是不可为空的,而我用来设置它的参数是可空的(尽管在设置时它不应该为空)。执行时返回值为 0。如果我在程序之外运行其中一个更新,它们会完美运行,因此我怀疑它与可空类型有关。

问题:

这可能是因为存储过程的参数可以为空,而我设置的字段不是吗?

如果不是,那会是什么?

【问题讨论】:

  • 如果您将这些插入和更新更改为选择,您是否返回提供的参数的数据?
  • 是的。我更新了我的问题,添加了“如果我在程序之外运行其中一个更新,它们会完美运行,因此我怀疑它与可空类型有关。”
  • 1) 我稍微澄清了我的问题。我不想做输出参数。 2)存储过程说它执行并返回0,但值永远不会更新。我不确定您所说的“通过 sql 块”是什么意思。
  • 如果您通过 sql 块执行它,您的 SP 会执行吗?在您的情况下,由于您已硬编码 Cmd.Parameters["@Value"].IsNullable = true; Cmd.Parameters["@Value"].Value = DBNull.Value;,因此您不妨省略它。

标签: sql-server stored-procedures sql-server-2008-r2


【解决方案1】:

看起来您为除 PropertyValueID 和 DropDownOptionID 之外的每个参数都传递了 Null,对吗?如果只有这两个值不为空,我认为您的任何 IF 语句都不会触发。总之,我认为你有一个逻辑错误。

除此之外,我会建议两件事......

首先,不要测试 NULL,而是在 if 语句中使用这种语法(这样更安全)...

    ELSE IF ISNULL(@UnitValue, 0) != 0 AND ISNULL(@UnitOfMeasureID, 0) = 0

其次,在每个 UPDATE 之前添加一个有意义的 PRINT 语句。这样,当您在 MSSQL 中运行 sproc 时,您可以查看消息并了解它实际执行了多长时间。

【讨论】:

  • 哇,我觉得自己很笨。应该是 ELSE IF @DropDownOptionID IS NOT NULL 和其他人一样:/ 谢谢。
  • 使用ISNULL(...... IS NULL 更安全吗?您的建议似乎较少安全,因为至少出于一个原因,现在您有一个神奇的值(零),它被视为等同于NULL。如果您打算使用或允许空值,则测试NULL 并且仅测试NULL 是最安全的做法。
【解决方案2】:

您可以/应该将您的参数设置为 DBNull.Value;

if (variable == "")
{
     cmd.Parameters.Add("@Param", SqlDbType.VarChar, 500).Value = DBNull.Value;
}
else
{
     cmd.Parameters.Add("@Param", SqlDbType.VarChar, 500).Value = variable;
}

或者您可以将服务器端设置为 null 并且根本不传递参数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-11
    • 2010-12-21
    • 2015-04-24
    • 2012-02-02
    相关资源
    最近更新 更多