SQL Server存储过程Nullable参数

She*_*115 18 sql-server stored-procedures sql-server-2008-r2

问题:
当向下面的脚本提供值然后使用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
Run Code Online (Sandbox Code Playgroud)

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

执行示例:

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
Run Code Online (Sandbox Code Playgroud)

细节:

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

问题(S):

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

如果没有,它会是什么?

Ash*_*087 10

看起来你除了PropertyValueID和DropDownOptionID之外,每个参数都传入Null,对吗?如果只有这两个值不为null,我认为你的IF语句都不会触发.简而言之,我认为你有一个逻辑错误.

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

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

    ELSE IF ISNULL(@UnitValue, 0) != 0 AND ISNULL(@UnitOfMeasureID, 0) = 0
Run Code Online (Sandbox Code Playgroud)

其次,在每个UPDATE之前添加一个有意义的PRINT语句.这样,当您在MSSQL中运行sproc时,您可以查看消息并查看它实际获得的距离.

  • 如何使用`ISNULL(......比'IS更安全?'IS NULL`?看起来你的建议不那么安全,因为至少有一个原因,现在你有一个被处理的魔法值(零)相当于`NULL`.如果你要使用或允许空值,测试`NULL`和只有'NULL`是最安全的事情. (13认同)

use*_*975 5

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

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

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