什么对我的DECIMAL列中的值取整?

时间:2018-11-22 09:33:27

标签: sql-server ado.net

我有一个SQL更新请求。我希望它仅修改更新模型中为其提供值的列,因此我使用常规形式myCol = ISNULL(@myParam, myCol)。这是完整的SQL ...

update Justif set 
DateTransaction = ISNULL(@dateTransaction,DateTransaction),
Cif = ISNULL(@cif,Cif),
NomFournisseur = ISNULL(@nomFournisseur,NomFournisseur),
MontantHT = ISNULL(@montantHT,MontantHT),
MontantTtc = ISNULL(@montantTtc,MontantTtc),
TauxTva = ISNULL(@tauxTva,TauxTva),
MontantTva = ISNULL(@montantTva,MontantTva),
ReceptionNumber = ISNULL(@receptionNumber,ReceptionNumber),
Locked = IIF(@locked > 0,GETDATE(),null),
Used = IIF(@used is not null, @used, Used),
NatureOcr = ISNULL(@natureOcr, NatureOcr)
where JustifID = @justifId

现在,最奇怪的事情是,应用程序在某一时刻使用此请求只是设置了列Used

montantTtc参数与所有其他参数一样,都用DBNull.Value初始化(并且SqlDbType设置为小数),然后令我惊讶的是,小数列四舍五入为最接近的{{1 }}。

我对int不了解?

enter image description here

1 个答案:

答案 0 :(得分:2)

再次触发参数类型推断。 Decimal的{​​{1}} SQL参数作为NULL传递。 DECIMAL(29,0)返回其第一个参数的类型,其余参数将由该参数负责。简短的代码片段可以重现/证明这一点:

ISNULL
  

Munged值:123
  精度:29
  比例尺:0

正确的解决方案是根据该列提供参数的using (var connection = new SqlConnection(@"Data Source=(localdb)\MSSQLLocalDB")) { connection.Open(); using (var command = new SqlCommand(@" DECLARE @v DECIMAL(4,1) = 123.4; SELECT ISNULL(@p, @v), SQL_VARIANT_PROPERTY(ISNULL(@p, @v), 'Precision'), SQL_VARIANT_PROPERTY(ISNULL(@p, @v), 'Scale')" )) { command.Connection = connection; command.Parameters.Add(new SqlParameter("@p", SqlDbType.Decimal)).Value = DBNull.Value; using (var reader = command.ExecuteReader()) { reader.Read(); Console.WriteLine($@" Munged value: {reader.GetValue(0)} Precision: {reader.GetValue(1)} Scale: {reader.GetValue(2)} "); } } } Precision。一种替代方法是使用

Scale

等效于以下形式的表达式

COALESCE(@p, @v)

两者都将应用CASE WHEN @p IS NOT NULL THEN @p ELSE @v END 升级规则(这将导致DECIMAL)。请注意,如果源类型具有很高的精度,则这是可能不安全的:使用DECIMAL(30,1)将得出DECLARE @v DECIMAL(17,10) = 123.0123456789的四舍五入DECIMAL(38,9)。唯一真正通用的解决方法是使用列的确切类型。