十进制DbType - 缩放和精度翻转?

时间:2015-05-18 12:43:39

标签: c# sql-server ado.net decimal dbtype

我有一个SQL Server存储过程,我从C#调用。

有些参数是Decimal,比例和精度各不相同,但最常见的是比例8和精度2。

所以我需要使用Decimal dbtype。

ALTER PROCEDURE [dbo].[SaveAssortmentPlanItem]
    @hierarchy                  nvarchar(13),
    @closing_store_stock        nvarchar(10),
    @closing_westway_stock      nvarchar(10),
    @sales_volume               decimal(8,2) = 0.00,
    @exit_code                  nvarchar(10),
    @name                       nvarchar(50),
    @medium_colour              nvarchar(50),
    @margin_percent             decimal(4,1) = 0.0,
    @retail_1st_on_sale_date    nvarchar(50),
    @new_continuing             nvarchar(10),
    @vendor                     nvarchar(50),
    @retail_initial_allocation  decimal(6,2) = 0.00,
    @no_of_stores               int,
    @total_planned_retail_closing_stock decimal(8,2) = 0.00,
    @fp_sales_value             decimal(8,2) = 0.00,
    @fp_margin_value            decimal(8,2) = 0.00
  AS ...

但是当我尝试使用标度为8且精度为2的Decimal参数调用该过程时,我得到的是一个错误:

Parameter value 0.00000000 is out of range

(此处的值为零)。

当发生这种情况时,甚至不会调用该过程,并且SQL跟踪中不会出现任何内容。

如果我使用精度8和比例2,它可以正常工作,即使这样,这与我期望的相反。

如果我从参数中读取值,它们看起来都符合预期!

这是我的主要功能代码:

        const string SAVE_ASSORTMENT_PLAN_ITEM = "dbo.SaveAssortmentPlanItem";

        DAL.Execute(SAVE_ASSORTMENT_PLAN_ITEM, new[]
        {
            // NOTE a few parameters removed for brevity
            DAL.ParamNVarchar("@hierarchy", hierarchy),
            DAL.ParamNVarchar("@closing_store_stock", closingStoreStock ?? ""),
            DAL.ParamDecimal("@sales_volume", salesVolume == "0" ? "1" : salesVolume, 8, 2),
            DAL.ParamNVarchar("@exit_code", exitCode ?? ""),
            DAL.ParamNVarchar("@name", name ?? ""),
            DAL.ParamNVarchar("@medium_colour", mediumColour ?? ""),
            DAL.ParamDecimal("@margin_percent", marginPercent, 4, 1),
            DAL.ParamNVarchar("@retail_1st_on_sale_date", retail1stOnSaleDate ?? ""),
            DAL.ParamNVarchar("@new_continuing", newContinuing ?? ""),
            DAL.ParamNVarchar("@vendor", vendor ?? ""),
            DAL.ParamDecimal("@retail_initial_allocation", retailInitialAllocation, 6, 2),
            DAL.ParamInt("@no_of_stores", noOfStores ?? "0"),
            DAL.ParamDecimal("@total_planned_retail_closing_stock", totalPlannedRetailClosingStock, 8, 2),
            DAL.ParamDecimal("@fp_sales_value", FPSalesValue, 8, 2),
            DAL.ParamDecimal("@fp_margin_value", FPMarginValue, 8, 2)
        }

执行功能是:

    public static void Execute(string procName, SqlParameter[] parameters = null)
    {
        const string BUY_ME_CONNECTION = "BuyMe";

        using (var connection = GetConnection(BUY_ME_CONNECTION))
        {
            connection.Open();

            var command = new SqlCommand(procName, connection) {CommandType = CommandType.StoredProcedure};
            if (parameters != null) command.Parameters.AddRange(parameters);

            command.ExecuteNonQuery();
        }
    }

...和ParamDecimal函数:

    public static SqlParameter ParamDecimal(string name, string value, byte scale, byte precision)
    {
        var decimalValue = decimal.Parse(value ?? "1", NumberStyles.AllowThousands | NumberStyles.AllowDecimalPoint);
        var result = new SqlParameter(name, SqlDbType.Decimal) { Value = decimalValue, Precision = precision, Scale = scale };
        return result;
    }

考虑到这里最不可能出现的情况是Scale和Precision值实际上是反转的,我已经通过我的代码看看我是否以某种方式翻转它,但这似乎并非如此。

还有什么可以导致这个问题?

2 个答案:

答案 0 :(得分:2)

以上是预期的,如果您有DECIMAL(2,8),则表示值不大于2位,并且 8位数位于右侧十进制,这没有意义。 SQL Server会在这种情况下抛出错误...

  

比例必须小于或等于精度。

切换为DECIMAL(8, 2)时,您说的值不大于8位小数点右侧的2位数 0.00000000 的结果为 0.00

答案 1 :(得分:1)

DAL.ParamDecimal("@sales_volume", salesVolume == "0" ? "1" : salesVolume, 8, 2)

根据此方法的定义,您使用scale = 8precision = 2进行调用。这将导致SQL类型DECIMAL(2,8) ...这显然是错误的。

精度是可以存储的有效位数,而缩放是小数部分后面的位数。

你想要的是DECIMAL(8,2),即精度为8,比例为2,所以切换参数:

DAL.ParamDecimal(…, scale: 2, precision: 8).