Decimal DbType - scale 和 precision flipped?
Decimal DbType - scale and precision flipped?
我有一个 SQL 服务器存储过程,我正在从 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 值实际上是相反的,我已经检查了我的代码以查看我是否以某种方式翻转它,但情况似乎并非如此。
还有什么可能会导致此问题?
以上是预期的,如果你有 DECIMAL(2,8)
,你说的是一个值 不大于 2 位数字,并且 8 位数字小数点右边,这没有意义。 SQL 服务器会在这种情况下抛出错误...
The scale must be less than or equal to the precision.
通过切换到 DECIMAL(8, 2)
,您表示一个值 不大于 8 位数字,小数点右边有 2 位数字。 0.00000000 的结果将是 0.00.
DAL.ParamDecimal("@sales_volume", salesVolume == "0" ? "1" : salesVolume, 8, 2)
根据这个方法的定义,你用scale = 8
和precision = 2
调用它。这将导致 SQL 类型 DECIMAL(2,8)
... 这显然是错误的。
精度是可以存储的有效位数,小数位数是小数点后的位数。
你想要的是 DECIMAL(8,2)
,即精度为 8,小数位数为 2,所以切换参数:
DAL.ParamDecimal(…, scale: 2, precision: 8).
我有一个 SQL 服务器存储过程,我正在从 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 值实际上是相反的,我已经检查了我的代码以查看我是否以某种方式翻转它,但情况似乎并非如此。
还有什么可能会导致此问题?
以上是预期的,如果你有 DECIMAL(2,8)
,你说的是一个值 不大于 2 位数字,并且 8 位数字小数点右边,这没有意义。 SQL 服务器会在这种情况下抛出错误...
The scale must be less than or equal to the precision.
通过切换到 DECIMAL(8, 2)
,您表示一个值 不大于 8 位数字,小数点右边有 2 位数字。 0.00000000 的结果将是 0.00.
DAL.ParamDecimal("@sales_volume", salesVolume == "0" ? "1" : salesVolume, 8, 2)
根据这个方法的定义,你用scale = 8
和precision = 2
调用它。这将导致 SQL 类型 DECIMAL(2,8)
... 这显然是错误的。
精度是可以存储的有效位数,小数位数是小数点后的位数。
你想要的是 DECIMAL(8,2)
,即精度为 8,小数位数为 2,所以切换参数:
DAL.ParamDecimal(…, scale: 2, precision: 8).