【问题标题】:Comma vs dot as decimal separator逗号与点作为小数分隔符
【发布时间】:2015-01-22 08:35:50
【问题描述】:

我有一个将一些数据写入 SQLite 数据库的 C# 应用程序,当我尝试将 C# double 存储到 SQLite REAL 字段时出现问题。

它使用逗号作为小数分隔符将其保存到数据库中(在我的国家通常,不确定它是否重要)。

表格结构如下:

CREATE TABLE `valoresStock` (
  `Fecha`   TEXT,
  `IdArticulo`  TEXT,
  `IdColor` INTEGER,
  `KgPorUnidad` REAL,
  `Stock`   REAL,
  `CostePorKg`  REAL,
  `CostePorUnidad`  REAL,
  PRIMARY KEY(Fecha,IdArticulo,IdColor)
);

我在应用中使用的查询如下:

cmd.CommandText = "INSERT INTO valoresStock (Fecha, IdArticulo, IdColor, KgPorUnidad, Stock, CostePorKg, costePorUnidad) VALUES ('" + DateTime.Today + "','" + referencia.idArticulo + "', '" + referencia.idColor + "', '" + referencia.kilos + "', '" + referencia.stockActual + "', '" + referencia.valorPorKg + "', '" + referencia.valorPorUnidad + "') ";

正如我所说,最后四个字段是 double 类型。没有给出错误。

那么数据存储如下:

也就是说,没有小数部分的时候用点,有小数的时候用逗号。

这个问题是例如当我使用SELECT语句来计算时,例如:

SELECT VS.Fecha, VS.IdArticulo, VS.IdColor, (VS.Stock * (VS.CostePorUnidad + VS.CostePorKg * Vs.KgPorUnidad)) AS Valor FROM valoresStock VS

这给出了以下结果,这是错误的(只取带点的数字)。

因此,如果我手动更改表格中点的逗号,它可以正常工作。

但是如何让我的应用做到这一点,某种文化改变?

或者我可以让 SQLite 理解或自动转换逗号吗?

如果 SQLite 以后不理解该数字,为什么它会接受该数字为有效数字?

【问题讨论】:

  • 又一个您应该使用参数化查询的机会。
  • 你能进一步解释一下吗?
  • 我已经在回答中描述过了。

标签: c# sqlite


【解决方案1】:

您应该使用参数化查询来插入值。这意味着您应该只在 SQL 字符串中使用参数占位符并将实际值添加为查询参数。

这通常是防止 SQL 注入攻击的好习惯。虽然这些在这里可能是一个较小的问题,但如果您的所有值都是数字的(甚至可能不直接来自用户输入),则此参数化还用于确保参数值的格式就像目标引擎想要/需要的那样。浮点数将被识别,您无需担心正确的小数分隔符,字符串将被识别而无需您担心正确的引号和转义。

因此,您的INSERT 语句应更改如下:

cmd.CommandText = "INSERT INTO valoresStock (Fecha, IdArticulo, IdColor, KgPorUnidad, Stock, CostePorKg, costePorUnidad)"
    + "VALUES (@fecha, @idArticulo, @idColor, @kgPorUnidad, @stock, @costePorKg, @costePorUnidad)";

然后,您可以将参数值添加到命令中,如下所示:

cmd.Parameters.AddWithValue("@fecha", DateTime.Today.ToString(System.Globalization.CultureInfo.InvariantCulture));
cmd.Parameters.AddWithValue("@idArticulo", referencia.idArticulo);
cmd.Parameters.AddWithValue("@idColor", referencia.idColor);
cmd.Parameters.AddWithValue("@kgPorUnidad", referencia.kilos);
cmd.Parameters.AddWithValue("@stock", referencia.stockActual);
cmd.Parameters.AddWithValue("@costePorKg", referencia.valorPorKg);
cmd.Parameters.AddWithValue("@costePorUnidad", referencia.valorPorUnidad);

所有浮点值将被自动识别并正确存储。

需要注意的是,我已将DateTime.Today 显式转换为字符串,原因有两个:

  • DateTime 不是原始类型,所以我不完全确定数据库引擎会对它做什么。
  • 您已将Fecha 列声明为具有TEXT 类型,因此我认为您需要数据库中日期的文本表示,而不是任何可以“评估”的内容。

为了确保您的程序写入相同的数据,无论在什么机器上执行,我都使用了InvariantCulture CultureInfo 实例,可以说是“中性”格式独立于当前机器的文化设置。如果您的程序也希望这种格式在您解析日期时使用,那么您的应用程序编写的数据库文件将始终兼容,即使该应用程序在具有不同文化设置的机器上使用时也是如此。

【讨论】:

  • 我将 Fecha 声明为 TEXT,因为 SQLite 没有日期的数据类型,如下所述:sqlite.org/datatype3.html 所以我按照它的建议使用 TEXT 作为 ISO8601 字符串(“YYYY-MM-DD HH: MM:SS.SSS")。
  • @Pinx0:哦,对了;在这种情况下,您可以将DateTime 转换为受支持的格式之一,而不是ToString(System.Globalization.CultureInfo.InvariantCulture),例如明确指定适当的格式字符串。 This SO question 提供了另一种方法。
【解决方案2】:

我可能是错的,但也许DefaultThreadCurrentCulture 属性可以帮助你。

【讨论】:

    【解决方案3】:

    我会在 .NET 端而不是在数据库端解决问题。

    在 .NET 中,数字格式取决于文化。例如:

    // This prints 2.3 - Neutral, invariant culture (English notation)
    string withDot = (2.3d).ToString(CultureInfo.InvariantCulture.NumberFormat);
    
    // This prints 2,3 - Spanish culture
    string withComma = (2.3d).ToString(new CultureInfo("es-ES"));
    

    【讨论】:

      猜你喜欢
      • 2017-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-05
      • 2015-10-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多