2012-10-15 36 views
0

我需要做些什么以适应Xml文档中最终被写为十进制(18,5),int或唯一标识符(可能没有数据)的传入值标签[虽然不是NULL数据 - 因为我发现硬的方式],或标签中的文本数据。看来我解决了一个问题,但创建了另一个问题!: - \我得到的错误:将转换varchar值'7800.00000'为数据类型int 时转换失败,转换失败时从字符串转换为uniqueidentifier。我该如何纠正?tsql:xml节点转换错误

下面是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); 

UPDATE:该线 -

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)), 

,以适应非数字/非空值和第一个非空的,我希望是一个小数 - 如果我得到一些其他的做作值仍可能爆破。有关如何处理这个问题的任何建议?

回答

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) 
+0

谢谢!数字测试不起作用。现在,唯一标识符有什么问题?该唯一标识符与此不兼容:从字符串转换为uniqueidentifier时转换失败...虽然不总是如此!: - \ – plditallo

+0

非常感谢您使用GUID纠正此问题。我确实回去编辑我的原始SELECT与十进制转换上的额外varchar。第一篇文章只是一个糟糕的剪贴工作。 – plditallo

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 
+0

有帮助,但在某些notnull被标记时失败isnull。 – plditallo

+0

我已经改变了脚本。我没有使用isnumeric函数,因为它有时无法正常工作 –