代码之家  ›  专栏  ›  技术社区  ›  Dela

MsSQL xml解析为十进制

  •  2
  • Dela  · 技术社区  · 7 年前

    我正在用这个存储过程处理xml

    select
        col.query('./AgreementId').value('.','uniqueidentifier') as [AgreementId],
        x.query('./GrossValue').value('.','decimal(19, 4)') as [GrossValue]
        into #AdvanceInvoices
        from @XML.nodes('/DataFromERP/CustomObjects/Agreements/Agreement') as ref(col)
        cross apply ref.col.nodes('AdvanceInvoices/AdvanceInvoice') as T(x)
    

    问题是GrossValue,它可以为空

    <GrossValue></GrossValue>
    

    也许当它是,我得到一个错误

    Error converting data type nvarchar to numeric
    

    我如何准备它以获得0.0而不是错误?

    编辑:

    我想到了

    CAST(COALESCE(NULLIF(ISNULL(x.query('./GrossValue').value('.','nvarchar(50)'),''),''),'0.0') as decimal(19,4)) as [GrossValue],
    

    但它非常丑陋

    2 回复  |  直到 6 年前
        1
  •  4
  •   Community CDub    4 年前

    很久以前 TRY_CAST TRY_CONVERT 发明了一个 XQuery 演员阵容:

    DECLARE @SomeTable TABLE(ID INT IDENTITY, SomeXML XML);
    INSERT INTO @SomeTable VALUES
     (N'<DATA><SomeNumber>1</SomeNumber></DATA>')     --integer
    ,(N'<DATA><SomeNumber>1.1</SomeNumber></DATA>')   --decimal
    ,(N'<DATA><SomeNumber></SomeNumber></DATA>')      --empty
    ,(N'<DATA><SomeNumber>abc</SomeNumber></DATA>')   --invalid
    ,(N'<DATA><SomeNumber>.123</SomeNumber></DATA>')  --short
    
    SELECT t.SomeXML.value(N'/DATA[1]/SomeNumber[1]/text()[1] cast as xs:decimal?',N'decimal(19,4)')
    FROM @SomeTable AS t
    

    使用 cast as xs:decimal? 将返回 NULL 当值不可浇铸时。

    为了得到 0.0 而不是 无效的 您可以使用 ISNULL() -功能(TT已经指出)。

    作为提示:

    在旧版本中 TRY_ 呼叫不起作用,这是一个很好的解决方法:

    DECLARE @InvalidNumber VARCHAR(100)='123a'
           ,@ValidNumber VARCHAR(100)='123';
    
    SELECT (SELECT @InvalidNumber FOR XML PATH(''),TYPE).value(N'. cast as xs:int?',N'int') AS InvalidNumber
          ,(SELECT @ValidNumber FOR XML PATH(''),TYPE).value(N'. cast as xs:int?',N'int') AS ValidNumber;
    

    或者更简单,只是演员阵容:

    DECLARE @InvalidNumber VARCHAR(100)='123a'
           ,@ValidNumber VARCHAR(100)='123';
    
    SELECT CAST(@InvalidNumber AS XML).value(N'. cast as xs:int?',N'int') AS InvalidNumber
          ,CAST(@ValidNumber AS XML).value(N'. cast as xs:int?',N'int') AS ValidNumber
    
        2
  •  2
  •   TT.    7 年前

    您可以尝试从元素中获取VARCHAR值,使用 TRY_CAST 如果值为NULL,则使用ISNULL获取0.0。

    ISNULL(TRY_CAST(x.query('./GrossValue').value('.','VARCHAR(20)') AS DECIMAL(19,4)),.0) AS [GrossValue]
    

    大概和我想的一样难看吧。