【问题标题】:How Does SQL Server Know What Precision To Display Real Data Types To?SQL Server 如何知道将真实数据类型显示到何种精度?
【发布时间】:2014-10-08 00:19:13
【问题描述】:

我正在尝试将表从远程 SQL 2000 数据库复制到我的本地 SQL 2012 实例中。

作为检查已更改值的快速方法,我使用了Simple Talk 上的“UNION ALL...GROUP BY”技术(向下滚动大约一半)。

不幸的是,远程数据类型设置为 REAL,因为这是一个近似数据类型,所以它不是很可靠,因为它会在我不希望的地方找到差异(即使这些差异在计算上存在)。

我尝试使用 CONVERT 将值更改为 NUMERIC(精确)数据类型。但是,不同的列具有不同的小数位数,因此很难找到一种万能的解决方案。

我注意到的一件事是,如果我运行以下查询(TimeID 是 INT,Value1 是 REAL):

SELECT [TimeID], [Value1], CONVERT(DECIMAL(19,10), [Value1]) AS [CONV19,10], CONVERT(DECIMAL(19,3), [Value1]) AS [CONV19,3], CONVERT(DECIMAL(19,4), [Value1]) AS [CONV19,4]
FROM   [DATABASE].[SCHEMA].[TABLE]
WHERE  [TimeID] = 12345

我得到以下结果:

[TimeID]     [Value1]     [CONV19,10]          [CONV19,3]        [CONV19,4]
12345        1126.089     1126.0885009766      1126.089          1126.0885

请注意,SQL Server Management Studio 将 Value1 显示为原始格式时保留 3 位小数(即无需我进行转换)。

所以我的问题是:SSMS 怎么知道它应该显示到小数点后 3 位?它怎么知道 1126.0885 不是实际存储的数字,而是 1126.089?

理想情况下,我想了解它的算法,以便我可以复制它以将我的数据转换为正确的小数位数。

【问题讨论】:

    标签: sql sql-server formatting


    【解决方案1】:

    这不会回答你的问题,但会给你一个自己回答的起点?

    首先阅读:

    http://msdn.microsoft.com/en-us/library/ms187912.aspx

    值得注意的是,“float 和 real 的行为遵循 IEEE 754 关于近似数值数据类型的规范。”

    现在阅读:

    http://en.wikipedia.org/wiki/IEEE_floating_point

    所以现在您应该知道浮点数/实数是如何存储的,以及为什么它们是“近似”数字。

    至于 SSMS 如何“知道”实数/浮点数中有多少小数,我真的不知道,但这与 IEEE 754 规范有关?

    一个简单的演示脚本是:

    DECLARE @MyNumber FLOAT(24) = 1.2345;
    SELECT @MyNumber, CONVERT(NUMERIC(19, 4), @MyNumber), CONVERT(NUMERIC(19, 10), @MyNumber), CONVERT(NUMERIC(19, 14), @MyNumber);
    

    【讨论】:

    • 感谢理查德的回复。我之前已经阅读了这两个链接,并且对 REAL 数据类型是近似的这一事实感到相当满意(希望我的示例转换显示了这一点)。在理想情况下,我会将远程数据库更改为 NUMERIC,但遗憾的是,这是由第三方提供且不可更改。在我看来,SSMS 知道要四舍五入,也许我需要尝试自己的调查以确定它是如何做到的。
    【解决方案2】:

    我不知道是否是这种情况,但我怀疑 SSMS 使用的是 .NET 数字字符串格式。

    我遇到了类似的情况,我只是想将SELECT 转换为VARCHAR,这与 SSMS 在查询结果网格中显示的内容完全相同。

    最后我得到了我想要的FORMAT函数,使用General format specifier

    例如:

    DECLARE @Floats TABLE([FloatColumn] FLOAT);
    INSERT INTO @Floats
    VALUES
    (123.4567),
    (1.23E-7),
    (PI());
    
    SELECT
    Number = f.FloatColumn,
    Text = FORMAT(f.FloatColumn, 'G'),
    IncorrectText = CONVERT(NVARCHAR(50), f.FloatColumn)
    FROM @Floats f;
    

    我必须提供免责声明,我不知道这是否会在所有情况下都按预期工作,但它适用于我需要的一切。

    我相信这在六年后非常有用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-20
      • 2023-03-24
      • 1970-01-01
      相关资源
      最近更新 更多