0

我需要做什么才能容纳 Xml 文档中的传入值,这些值最终被写入为十进制(18,5)、整数或标签中可能没有数据的唯一标识符 [尽管不是 NULL 数据--正如我发现的困难方式],或标签中的文本数据。似乎我解决了一个问题,但又创建了另一个问题!:-\ 我收到错误消息:将 varchar 值“7800.00000”转换为数据类型 int 时转换失败,从字符串转换为唯一标识符时转换失败。我该如何纠正?

这是带有数据的 xml 片段的示例:

<Products>
  <Product>
      <AgreementId>2439</AgreementId>
      <Difference>0.00400</Difference>
      <DispatchedQuantity>7800.00000</DispatchedQuantity>
      <Freight>0.01560</Freight>
      <ProductGUID>d475165c-0031-41f6-ad44-cecb73dfd2de</ProductGUID>
      <ShortName>U_B5Not Specif_No2_U</ShortName>
    </Product>
  </Products

这是在存储过程中处理它的代码:

 SELECT
       l.OrderId,
       l.OrderLiftId,
       cast(n.x.value('AgreementId[1]', 'varchar(20)') as int),
       CAST(CASE WHEN n.x.value('Difference[1]', 'varchar(20)') = '' THEN 0 ELSE  COALESCE(n.x.value('Difference[1]', 'varchar(20)'), '0.00') END AS decimal(18,5)),
       CAST(CASE WHEN n.x.value('DispatchedQuantity[1]', 'varchar(20)') = '' THEN 0 ELSE  COALESCE(n.x.value('DispatchedQuantity[1]', 'varchar(20)'), '0.00') END AS decimal(18,5)),
       CAST(CASE WHEN n.x.value('Freight[1]', 'varchar(20)') = '' THEN 0 ELSE  COALESCE(n.x.value('Freight[1]', 'varchar(20)'), '0.00') END AS decimal(18,5)),
       cast(n.x.value('ProductGUID[1]', 'varchar(40)') as uniqueidentifier),
       n.x.value('ShortName[1]', 'varchar(100)')
  FROM @lines as l
   CROSS APPLY l.lineprods.nodes('/Products/Product') as n(x);

更新:这一行——

 CAST(CASE WHEN n.x.value('DispatchedQuantity[1]', 'varchar(20)') = '' THEN 0 ELSE  COALESCE(n.x.value('DispatchedQuantity[1]', 'varchar(20)'), '0.00') END AS decimal(18,5)),

需要改为:

 CAST(CASE WHEN n.x.value('DispatchedQuantity[1]', 'varchar(20)') = '' THEN 0 ELSE  COALESCE(n.x.value('DispatchedQuantity[1]', 'decimal(18,5)'), '0.00') END AS decimal(18,5)),

容纳非数字/非空值和我希望是小数的第一个非空值——如果我得到其他一些虚假值,它仍然可能会爆炸。关于如何处理的任何建议?

4

2 回答 2

1

尝试这个。

declare @xml xml 

select @xml = '
<Products>
  <Product>
      <AgreementId>2439</AgreementId>
      <Difference>aaa</Difference>
      <DispatchedQuantity>7800.00000</DispatchedQuantity>
      <Freight>0.01560</Freight>
      <ProductGUID>d475165c-0031-41f6-ad44-cecb73dfd2de</ProductGUID>
      <ShortName>U_B5Not Specif_No2_U</ShortName>
    </Product>
  </Products>'

select
    CALC2.Agreement,
    CALC2.[Difference],
    CALC2.DispatchedQuantity,
    CALC2.ProductGUID,
    CALC2.Freight,
    CALC.ShortName
from @xml.nodes('/Products/Product') as n(x)
    outer apply
    (
        select
            isnull(n.x.value('AgreementId[1]', 'varchar(20)'), '0') as Agreement,
            isnull(n.x.value('Difference[1]', 'varchar(20)'), '0.00000') as     [Difference],
            isnull(n.x.value('DispatchedQuantity[1]', 'varchar(20)'), '0.00000') as DispatchedQuantity,
            n.x.value('ProductGUID[1]', 'varchar(40)') as ProductGUID,
            isnull(n.x.value('Freight[1]', 'varchar(20)'), '0.00000') as Freight,
            n.x.value('ShortName[1]', 'varchar(100)') as ShortName
    ) as CALC
    outer apply
    (
        select
            case when CALC.Agreement not like '%[^0-9]%' then cast(CALC.Agreement as int) else null end as Agreement,
            case when CALC.[Difference] not like '%[^0-9]%' then cast(CALC.[Difference] as decimal(18,5)) else null end as [Difference],
            case when CALC.DispatchedQuantity not like '%[^0-9]%' then null else cast(CALC.DispatchedQuantity as decimal(18,5)) end as DispatchedQuantity,
            cast(CALC.ProductGUID as uniqueidentifier) as ProductGUID,
            case when CALC.Freight not like '%[^0-9]%' then null else cast(CALC.Freight as decimal(18,5)) end as Freight
    ) as CALC2
于 2012-10-15T18:26:37.200 回答
1

我想ISNUMERIC函数可以解决问题。

CASE WHEN ISNUMERIC(n.x.value('DispatchedQuantity[1]', 'varchar(max)')) = 0 THEN 0 ELSE ... END

但是,我不明白您为什么在将 xml 转换为十进制之前将其提取为 varchar(20)。确定数据是数字后,您可以简单地使用:

n.x.value('DispatchedQuantity[1]', ' decimal(18,5)')

我用于测试的完整 SQL:

DECLARE @XML XML
SET @XML = '<Products>
              <Product>
                  <AgreementId>2439</AgreementId>
                  <Difference>0.00400</Difference>
                  <DispatchedQuantity>7800.00000</DispatchedQuantity>
                  <Freight>0.01560</Freight>
                  <ProductGUID>d475165c-0031-41f6-ad44-cecb73dfd2de</ProductGUID>
                  <ShortName>U_B5Not Specif_No2_U</ShortName>
                </Product>
                <Product>
                  <AgreementId>2439</AgreementId>
                  <Difference></Difference>
                  <DispatchedQuantity>INVALID NUMBER</DispatchedQuantity>
                  <Freight>INVALID FREIGHT</Freight>
                  <ProductGUID>INVALID GUID</ProductGUID>
                  <ShortName>U_B5Not Specif_No2_U</ShortName>
                </Product>
              </Products>'

SELECT  [AgreementId] = CAST(n.x.value('AgreementId[1]', 'varchar(20)') AS INT),
        [Difference] = CAST(CASE WHEN ISNUMERIC(n.x.value('Difference[1]', 'varchar(max)')) = 0 THEN 0 ELSE n.x.value('Difference[1]', 'decimal(18, 5)') END AS DECIMAL(18,5)),
        [DispatchedQuantity] = CAST(CASE WHEN ISNUMERIC(n.x.value('DispatchedQuantity[1]', 'varchar(max)')) = 0 THEN 0 ELSE n.x.value('DispatchedQuantity[1]', 'decimal(18, 5)') END AS DECIMAL(18,5)),
        [Freight] = CAST(CASE WHEN ISNUMERIC(n.x.value('Freight[1]', 'varchar(20)')) = 0 THEN 0 ELSE n.x.value('Freight[1]', ' decimal(18,5)') END AS DECIMAL(18,5)),
        [ProductGUID] = CASE WHEN ProductGUID LIKE Expression + '%' OR ProductGUID LIKE '{' + Expression + '}' THEN CAST(ProductGUID AS UNIQUEIDENTIFIER) END,
        [ShortName] = n.x.value('ShortName[1]', 'varchar(100)')
FROM    @XML.nodes('/Products/Product') AS n(x)
        CROSS APPLY 
        (   SELECT  [ProductGUID] = n.x.value('ProductGUID[1]', 'varchar(40)') ,
                    [Expression] = REPLACE('00000000-0000-0000-0000-000000000000', '0', '[0-9a-fA-F]') COLLATE Latin1_General_BIN 
        ) Expr 

编辑

我已经编辑了上面的查询以允许无效的 GUID(在Martin Smith的帮助下)

如果您使用的是 SQL-Server 2012,那么您可以使用TRY_CONVERT

SELECT  [AgreementId] = TRY_CONVERT(INT, n.x.value('AgreementId[1]', 'varchar(20)')),
        [Difference] =TRY_CONVERT(DECIMAL(18, 5), n.x.value('Difference[1]', 'varchar(max)')),
        [DispatchedQuantity] = TRY_CONVERT(DECIMAL(18, 5), n.x.value('DispatchedQuantity[1]', 'varchar(max)')),
        [Freight] = TRY_CONVERT(DECIMAL(18, 5), n.x.value('Freight[1]', 'varchar(20)')),
        [ProductGUID] = TRY_CONVERT(UNIQUEIDENTIFIER, n.x.value('ProductGUID[1]', 'varchar(40)')),
        [ShortName] = n.x.value('ShortName[1]', 'varchar(100)')
FROM    @XML.nodes('/Products/Product') AS n(x)
于 2012-10-15T19:11:16.353 回答