格式 'G17' 与 'G'

Cad*_*oux 7 sql-server sql-server-2012

我有一个关于这个小提琴的问题:

DECLARE @TestVal AS float = 8.88;
SELECT flt = @TestVal
    , xml = (SELECT Value = @TestVal FOR XML PATH(''), TYPE)
    , fmt17 = FORMAT(@TestVal, 'G17')
    , fmt = FORMAT(@TestVal, 'G')
    , cst = CAST(@TestVal AS nvarchar(50))
    , fmt17_roundtrip = CAST(FORMAT(@TestVal, 'G17') AS float)
    , fmt_roundtrip = CAST(FORMAT(@TestVal, 'G') AS float)
    , cst_roundtrip = CAST(CAST(@TestVal AS nvarchar(50)) AS float)
;
Run Code Online (Sandbox Code Playgroud)

https://dbfiddle.uk?rdbms=sqlserver_2019&fiddle=0cf05f882eb24f53e9484f043af99446

我在默认情况下以科学记数法输出某些 XML 时遇到了麻烦,虽然这些 XML 不正确或不准确,但可读性并不差。

我最初使用 FORMAT(floatcol, 'G17') 因为这个文档页面上的评论:

请注意,当与 Double 值一起使用时,“G17”格式说明符可确保原始 Double 值成功往返。这是因为 Double 是符合 IEEE 754-2008 标准的双精度 (binary64) 浮点数,可提供多达 17 位有效数字的精度。我们建议使用它而不是“R”格式说明符,因为在某些情况下,“R”无法成功地往返双精度浮点值。下面的例子说明了一种这样的情况。

好吧,今天我发现它似乎在字符串中添加了一些额外的无意义数字。在这个特定的例子中,它们都“往返”很好,但 G17 格式有一个额外的微不足道的数字。

尽管它可能不会影响我的往返行程,但我真的不想将它发送给具有额外数​​字的另一方。

现在我倾向于更改为 FORMAT('G'),但不确定其含义。目前,这些 XML 导出中使用的格式字符串是存储在我系统中的配置设置,因此继续使用 FORMAT 是最容易的,因为它不需要更改代码。

因此,在我对各种其他值进行测试之前,我的问题是 G 和 G17 之间的总体区别是什么,我可能会遇到使用 G 而不是 G17 的问题?

(是的,该值必须是浮点数,而不是小数或整数或货币,并且浮点数的域可能因不同的度量/上下文而异)。

系统确实需要在 2012 及更高版本上运行。

Mik*_*son 6

我的问题是总体上 G 和 G17 之间有什么区别,我可能会遇到使用 G 而不是 G17 的问题?

抱歉不知道,但你可以尝试用 XML 做一些事情。不确定这是否可以使用,但无论如何都在这里。

在处理类型化 XML 时,您将不会获得您的值的科学计数法,您将获得其他值的科学记数法。因此,使用类型化 XML 并将生成的 XML 分配给绑定到模式的 XML 变量,使用 xs:double 实现双精度。

这是一个架构。

create xml schema collection SC_F as '  
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="F" type="xs:double">
    </xs:element>
</xs:schema>
';  
Run Code Online (Sandbox Code Playgroud)

以及使用架构的查询。

declare @TestVal float = 8.88;
declare @X xml(SC_F);
set @X = (select @TestVal as F for xml path(''), type);
select @X;
Run Code Online (Sandbox Code Playgroud)

结果:

<F>8.88</F>
Run Code Online (Sandbox Code Playgroud)

使用 XML 修复它的另一种方法是将浮点值转换为 XML,然后将 XML 用作 XML 查询的值。现在听起来比实际复杂,我希望。

declare @TestVal float = 8.88;
select cast('' as xml).query('sql:variable("@TestVal")');
Run Code Online (Sandbox Code Playgroud)

结果

8.88
Run Code Online (Sandbox Code Playgroud)

下面是一些代码,显示了不同解决方案的不同输出。根据值,您最终将获得所有方法的科学记数法。

declare @T table(F float not null);

insert into @T(F) values(8.88),(0),(0.0001),(0.00001),(0.000001),
  (0.0000001),(0.84551240822557006);

declare @X1 xml;
declare @X2 xml(SC_F);
declare @X3 xml;
declare @X4 xml;
declare @X5 xml;

set @X1 = (select F from @T for xml path(''));
set @X2 = (select F from @T for xml path(''));
set @X3 = (select cast('' as xml).query('sql:column("F")') as F from @T for xml path(''));
set @X4 = (select format(F, 'G') as F from @T for xml path(''));
set @X5 = (select format(F, 'G17') as F from @T for xml path(''));

select @X1 as ScienceAllTheWay, 
       @X2 as UsingASchema, 
       @X3 as XMLTrickery,
       @X4 as FormatG,
       @X5 as FormatG17;
Run Code Online (Sandbox Code Playgroud)

结果:

科学一路

<F>8.880000000000001e+000</F>
<F>0.000000000000000e+000</F>
<F>1.000000000000000e-004</F>
<F>1.000000000000000e-005</F>
<F>1.000000000000000e-006</F>
<F>1.000000000000000e-007</F>
<F>8.455124082255701e-001</F>
Run Code Online (Sandbox Code Playgroud)

使用架构

<F>8.88</F>
<F>0</F>
<F>0.0001</F>
<F>1E-05</F>
<F>1E-06</F>
<F>1E-07</F>
<F>0.84551240822557006</F>
Run Code Online (Sandbox Code Playgroud)

XML技巧

<F>8.88</F>
<F>0.0E0</F>
<F>0.0001</F>
<F>0.00001</F>
<F>0.000001</F>
<F>1.0E-7</F>
<F>0.84551240822557</F>
Run Code Online (Sandbox Code Playgroud)

格式G

<F>8.88</F>
<F>0</F>
<F>0.0001</F>
<F>1E-05</F>
<F>1E-06</F>
<F>1E-07</F>
<F>0.84551240822557</F>
Run Code Online (Sandbox Code Playgroud)

格式G17

<F>8.8800000000000008</F>
<F>0</F>
<F>0.0001</F>
<F>1.0000000000000001E-05</F>
<F>9.9999999999999995E-07</F>
<F>9.9999999999999995E-08</F>
<F>0.84551240822557006</F>
Run Code Online (Sandbox Code Playgroud)