I have a SQL Server stored proc which I'm calling from C#.
Some of the parameters are Decimal
, scale and precision vary but most often these are scale 8 and precision 2.
So I need to use the Decimal
dbtype for these.
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 ...
However when I try to call the procedure with a Decimal parameter with scale of 8 and precision 2, what I get is an error:
Parameter value 0.00000000 is out of range
(the value here is zero).
When this happens the procedure isn't even called and nothing appears in the SQL trace.
If I use precision 8 and scale 2, it works fine, even thouse this is the reverse of what I would expect.
If I read the values from the parameters they all appear to be as expected!
This is my main function code:
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)
}
The Execute function is:
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();
}
}
...and the ParamDecimal function:
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;
}
Considering that the least likely scenario here is the Scale and Precision values are actually reversed I have been through my code to see if I am flipping it somehow but this doesn't seem to be the case.
What else could be going on to cause this problem?
The above is expected, if you have DECIMAL(2,8)
, you're saying a value no larger than 2 digits , and with 8 digits to the right of the decimal , which doesn't make sense. SQL Server would throw an error in this scenario...
The scale must be less than or equal to the precision.
By switching to DECIMAL(8, 2)
, you're saying a value no larger than 8 digits , with 2 digits to the right of the decimal . The result for 0.00000000 would be 0.00 .
DAL.ParamDecimal("@sales_volume", salesVolume == "0" ? "1" : salesVolume, 8, 2)
According to the definition of this method, you are calling it with scale = 8
and precision = 2
. This will result in a SQL type DECIMAL(2,8)
… which is obviously wrong.
The precision is the number of significant digits that can be stored, and the scale is the number of digits after the decimal fraction.
What you want is a DECIMAL(8,2)
, ie a precision of 8 and a scale of 2, so switch the arguments:
DAL.ParamDecimal(…, scale: 2, precision: 8).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.