2012-10-15 69 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函數,因爲它有時無法正常工作 –