【问题标题】:Storing UK pound sterling in a database在数据库中存储英镑
【发布时间】:2017-04-29 11:57:07
【问题描述】:

我从未在数据库中使用过以下货币。我做了一些研究,告诉我你应该使用 Decimal 数据类型。请参阅下面的 DDL:

create table dbCurrency (id int not null identity, CurrencyValue decimal (4,2), primary key (id))
insert into dbCurrency (CurrencyValue) values (50);
insert into dbCurrency (CurrencyValue) values (20);
insert into dbCurrency (CurrencyValue) values (10);
insert into dbCurrency (CurrencyValue) values (5);
insert into dbCurrency (CurrencyValue) values (2);
insert into dbCurrency (CurrencyValue) values (1);
insert into dbCurrency (CurrencyValue) values (0.5);
insert into dbCurrency (CurrencyValue) values (0.2);
insert into dbCurrency (CurrencyValue) values (0.1);
insert into dbCurrency (CurrencyValue) values (0.05);
insert into dbCurrency (CurrencyValue) values (0.02);
insert into dbCurrency (CurrencyValue) values (0.01);

这会存储所有英国货币。这是正确的方法吗。我问的原因是因为与我交谈过的人建议数据类型应该是:decimal (5,2) 而不是decimal (4,2). He knew I was storing currencies up to £50.

另外,假设我有两个 C# 小数:

decimal first;
decimal second;
decimal third;

假设我想将第一个小数除以第二个小数得到第三个小数。第三个小数点也是 c# 十进制数据类型吗?第一个小数总是大于第二个,结果可能是小数。第一位和第二位小数是货币值。

【问题讨论】:

  • 为什么他们建议你应该存储 5 位数,而明确表示你只会存储 4 位数?
  • @Rob,这就是我的困惑。
  • 你问过他们吗?
  • @Rob,不幸的是,我只会在下周末再次见到他们。我现在需要开始这项工作。
  • Yor edit 是一个单独的问题,处理 C# 而不是 SQL。请照此张贴。

标签: sql sql-server


【解决方案1】:

你选择了decimal() 而不是money/smallmoney,所以你已经过了第一个障碍。

一般情况下,建议选择decimal()(与numeric()相同,具有您需要的精度和规模。在这种情况下,decimal(4,2)可以,因为最大存储值不会超过precisionscale

decimal(4,2)decimal(5,2)decimal(9,2) 之间没有存储大小差异。

decimal的存储大小基于precision

+-----------+---------------+
| Precision | Storage bytes |
+-----------+---------------+
| 1 - 9     |             5 |
| 10-19     |             9 |
| 20-28     |            13 |
| 29-38     |            17 |
+-----------+---------------+

当您在 SQL Server 中执行某些操作时,precisionscale 可能会发生变化。在您的示例中,当您将decimal1 除以decimal2 时,您的返回类型将为decimalprecisionscale 将由下表确定:

+------------------------------+-------------------------------------+----------------+
|          Operation           |          Result precision           | Result scale * |
+------------------------------+-------------------------------------+----------------+
| e1 + e2                      | max(s1, s2) + max(p1-s1, p2-s2) + 1 | max(s1, s2)    |
| e1 - e2                      | max(s1, s2) + max(p1-s1, p2-s2) + 1 | max(s1, s2)    |
| e1 * e2                      | p1 + p2 + 1                         | s1 + s2        |
| e1 / e2                      | p1 - s1 + s2 + max(6, s1 + p2 + 1)  | max(6,s1+p2+1) |
| e1 union|except|intersect e2 | max(s1, s2) + max(p1-s1,p2-s2)      | max(s1, s2)    |
| e1 % e2                      | min(p1-s1, p2 -s2) + max( s1,s2 )   | max(s1, s2)    |
+------------------------------+-------------------------------------+----------------+

* 结果精度和小数位数的绝对最大值为 38。当结果精度大于 38 时,相应的小数位数会减小,以防止结果的整数部分被截断。

因此选择decimal(4,2) 可能会产生一些影响,具体取决于值将涉及的操作,但两者之间的任何性能差异都可以忽略不计。

参考:


在 C# 中,小数除以小数返回小数;小数除以整数返回小数;小数除以浮点数会返回错误,而无需显式转换。

【讨论】:

    【解决方案2】:

    这会存储所有英国货币。这是正确的做法吗?

    您存储的不是货币 - 您存储的是假定货币的面值(或官方纸币和硬币的面值)。这是否“正确”取决于您正在建模的内容 - 除了您之外没有人知道。我会同意@SqlZim 关于数据类型的看法。

    我确实对标识列的有用性持强烈的保留态度。它是否有目的,或者您是否将标识列添加到每个表中作为标准做法?至少,您应该强制执行自然密钥。

    根据 Wikipedia,您可能会遗漏一些价值,并且在价值方面,纸币和硬币之间存在一些重叠。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多