【问题标题】:SQL Server: what to do when a decimal isn't really a decimal?SQL Server:当小数不是真正的小数时该怎么办?
【发布时间】:2013-10-30 01:44:55
【问题描述】:

我有一种情况,十进制数字不是真正的小数,它是排序的子计数。例如,在填写药物处方时,会给出一个 Rx 编号(比如说 345673)。该号码将在任何笔芯期间与处方保持一致,并且笔芯会附加 0.1、0.2 等。因此,在该 Rx 编号的整个生命周期内,您最终可能会得到 345673、345673.1、345673.2... 持续进行中。问题是当您点击 .10、.20、.30 等时。在十进制格式中,这些记录与 .1、.2、.3 相同。

有什么方法可以在不使用VARCHAR 等的情况下跟踪这些数字并支持尾随零?这是主键列,我不喜欢在 Pk 上使用 varchar(这是老式的吗?)

感谢任何和所有建议/帮助。

编辑添加:我应该解释为什么我们不能为此使用单独的列。此数据源自其他地方,并通过批量导入操作合并到我们的数据库中。合并是永久性的,因为大部分数据在源头被更改并在下一次批量导入时合并。 Rx 编号必须完全匹配才能执行批量导入/合并。

【问题讨论】:

  • 使用 varchar,或使用带有组合键的 2 列。我不喜欢在同一列中组合不同的数据元素。一个是Rx Number,另一个是refills。对我来说似乎是两个数据元素。但是,如果必须,将 Varchar 作为 PK 很好。只是不要指望在现场做数学,或者如果你必须做数学,总是通过一个通用函数来做,这样以后很容易调整。不确定您使用的 MSFT 版本是否支持基于函数的索引,但这些也可能满足您的需求(与计算列一起使用)
  • 我应该解释为什么我们不能为此使用单独的列。此数据源自其他地方,并通过批量导入操作合并到我们的数据库中。合并是永久性的,因为大部分数据在源头被更改并在下一次批量导入时合并。 Rx 编号必须完全匹配才能执行批量导入/合并。我会把这个添加到问题中。
  • 必须是主键吗?您可以有一个简单的 id int identity(1,1) not null 作为 PK 和一个唯一的非聚集索引上的 Rx 编号,但这种变化可能超出您的要求。
  • @jgiven 然后我又开始使用 Varchar。真正的答案是了解数据是如何到达你的。如果他们将其视为 varchar,您也应该这样做。当再填充达到 10 或 20 时它们如何处理的问题只是在函数中处理它。当且仅当您必须对其进行数学运算时。否则它只显示数据,为什么要麻烦?为什么要与行业已经弄清楚的事情作斗争。
  • 你曾经对这些数字进行过数学运算吗?我认为这极不可能,就像你不太可能对电话号码进行数学运算一样。出于同样的原因,我推荐varchar - 它们字符串,恰好由一系列数字组成。您不应该将它们视为数字。

标签: sql sql-server decimal varchar


【解决方案1】:

我建议使用composite primary key。添加第二列,可能称为refill,并将其用于增量值。这样,两列都是整数,无需使用 varchar 作为主键。

您可能需要使用trigger 来维护该值,因为identity 字段不适用于分组。

【讨论】:

  • 谢谢...专栏不是同一个人,只是PK。由于它起源于其他地方,我们无法控制 Rx + Refill 的组合。这种组合也是行业的标准做法。
  • 绕了一圈之后,我想我将结合计算列来试一试。以前从未真正考虑过复合主键。谢谢。
【解决方案2】:

使用CONVERTCAST 将小数转换为varchar。然后可以使用LEFT()SUBSTRING()REPLACE()等字符/字符串函数。

另一种选择是使用数学解析出小数:

DECLARE @RxValue decimal(18,4) = 100.234
SELECT @RxValue [Rx Number]
    ,@RxValue - CONVERT(int,@RxValue) [Refill Count Decimal]
    ,LEN(CONVERT(float,(@RxValue - CONVERT(int,@RxValue))))-2 [After Decimal Length]
    ,POWER(10, LEN(@RxValue - CONVERT(int,@RxValue))-2) [Calc multiplier for Refill Count]
    ,CONVERT(int,@RxValue) [Rx ID]
    ,CONVERT(int,(@RxValue - CONVERT(int,@RxValue)) * POWER(10, LEN(CONVERT(float,(@RxValue - CONVERT(int,@RxValue))))-2)) [Refill Count]

上述选择中的最后两列是您想要的两列。以上只是我试图“展示我的作品”,这样你就可以看到我在想什么。 “-2”是为了去掉“0”。在LEN() 函数的结果中。 POWER() 函数将 10 取为十进制结果的幂。

您只需要将所有对@RxValue 的引用替换为您的“Rx 编号”的列名即可使其正常工作。如果您想尝试一下,可以将@RxValue 中的值更改为您想要的任何值,并确保结果符合您的预期。 确保更改 @RxValue 的数据类型以匹配您的数据类型。

如果是这种情况,您当然可以将“Rx 编号”保留为 PK。您只需添加几个派生列:[Rx ID][Refill Count]

如果您有任何问题,请发表评论。

【讨论】:

  • 感谢 coge.soft 的详细解释。我不认为这会是我在这种确切情况下使用的东西,但从中学习的机会让我对如何处理其他一些即将到来的棘手问题有了一些想法。
猜你喜欢
  • 1970-01-01
  • 2014-03-04
  • 1970-01-01
  • 2015-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多