C# 如何向数据表添加精确的差异列?

C# 如何向数据表添加精确的差异列?,c#,ado.net,C#,Ado.net,我需要比较具有相同模式的两个数据表中的数字数据。 例如,包含以下数据的两个表 PKColumn | numCol | DecimalCol 合并后会变成这样 PKColumn | numCol 1 | numCol 2 | numCol Diff | DecimalCol 1 | DecimalCol 2 | DecimalCol Diff 最初,我只是将diff列创建为一个表达式col1-col2,但最终可能会得到一些不寻常的值 col1 col2 diff c1

我需要比较具有相同模式的两个数据表中的数字数据。 例如,包含以下数据的两个表

PKColumn | numCol | DecimalCol

合并后会变成这样

PKColumn | numCol 1 | numCol 2 | numCol Diff | DecimalCol 1 | DecimalCol 2 | DecimalCol Diff

最初,我只是将diff列创建为一个表达式col1-col2,但最终可能会得到一些不寻常的值

col1    col2    diff        c1      c2      diff
12.8    14.6    -1.80000019 33.2    29.8    3.40000153
但我想要的是:

col1    col2    diff        c1      c2      diff
12.8    14.6    -1.8        33.2    29.8    3.4
因此,我当前的解决方案是手动迭代行,并使用以下方法设置值:

private static void SetDifference(DataRow dataRow, DataColumn numericColumn)
{
    dynamic value1 = dataRow[numericColumn.Ordinal - 2];
    dynamic value2 = dataRow[numericColumn.Ordinal - 1];

    if (IsDbNullOrNullOrEmpty(value1) || IsDbNullOrNullOrEmpty(value2)) return;

    //now find out the most decimals used and round to this value
    string valueAsString = value1.ToString(CultureInfo.InvariantCulture);

    int numOfDecimals = valueAsString.SkipWhile(c => c != '.').Skip(1).Count();

    valueAsString = value2.ToString(CultureInfo.InvariantCulture);

    numOfDecimals = System.Math.Max(numOfDecimals, valueAsString.SkipWhile(c => c != '.').Skip(1).Count());

    double result = Convert.ToDouble(value1 - value2);

    dataRow[numericColumn] = System.Math.Round(result, numOfDecimals);
}
但它感觉笨重,性能不好。欢迎提出改进建议

编辑:将列名从“int”更改为“num”,以避免混淆


编辑:此外,我不想总是四舍五入到小数点后一位。我可能有numA:28 numB:75.7999954这样的数据,所以我希望差值为:-47.7999954

您应该在sql查询中使用

ROUND(table1.IntCol 1 - table2.IntCol 2, 1)

如果有存储整数的列,请使用整数类型!您可能使用了单精度浮点类型。十进制类型也是如此。对它们使用十进制列类型,此舍入问题将消失

如果使用真正的十进制类型(不是浮点型、单精度型、实数型或双精度型),则不会遇到舍入问题。我不知道您正在使用哪个数据库,但对于SQL Server,正确的列类型应该是
decimal


更新

由于无法更改列类型,请将其四舍五入到要求的精度,如下所示

result = Math.Round((c1-c2) * 10)/10; // One decimal
result = Math.Round((c1-c2) * 100)/100; // Two decimals
result = Math.Round((c1-c2) * 1000)/1000; // Three decimals
试验

12.8f-14.6f===>-1.8000019 (十进制)12.8f-(十进制)14.6f==>-1.8
根据Olivier的评论,我更新了代码,如下所示:

if(numericColumn.DataType == typeof(int))
{
    dataRow[numericColumn] = System.Math.Abs(value1 - value2);
}
else
{
    dataRow[numericColumn] = Convert.ToDecimal(value1) - Convert.ToDecimal(value2);
}
看起来干净多了,它完成了任务。
感谢您的帮助。

这是我以数据集的形式收到的通用数据。数据没有数据库源。int列怎么可能是
12.8
?这只是为了强调列可以是多种数据类型。我对int列没有问题。“int”通常意味着只存储像
1
2
3
100
-77
17924
这样的数字,但肯定不会存储
12.8
。我没有使用任何数据库。我收到两份数据集形式的报告,这些数据集是基于一些实体数据创建的。我无法控制报告中包含的数据。我想知道report1中的数字数据和report2中的数字数据之间的差异。通常,所有数据都定义为“float”,但我希望它能够处理任何数据类型。我不想进行舍入,我只想得到数学上正确的差异。
float
类型的精度非常有限,并且会给您带来这些舍入错误。即使仅仅存储像
1.1
这样的值,也不能用
float
准确表示,因为
1/10
不能用
0
s和
1
s的有限序列来表示,并且使用内部二进制表示法。
decimal result = (decimal)col1 - (decimal)col2;
12.8f - 14.6f ===> -1.80000019 (decimal)12.8f - (decimal)14.6f ===> -1.8
if(numericColumn.DataType == typeof(int))
{
    dataRow[numericColumn] = System.Math.Abs(value1 - value2);
}
else
{
    dataRow[numericColumn] = Convert.ToDecimal(value1) - Convert.ToDecimal(value2);
}