我需要做什么才能容纳Xml doc上的传入值,这些值最终被写为十进制(18,5),int或唯一标识符,这些标识符可能在标记内没有数据[虽然不是NULL数据 - 因为我发现了困难的方式],或标签中的文本数据。似乎我解决了一个问题,但创建另一个问题!: - 我收到错误:转换varchar值时转换失败' 7800.00000'到数据类型int 从字符串转换为uniqueidentifier时转换失败。我该如何纠正?
以下是带有数据的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)),
以容纳非数字/非空值和第一个非空的,我希望是一个小数 - 如果我得到一些其他的hokey值,它仍然可能会爆炸。关于如何处理的任何建议?
答案 0 :(得分: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
答案 1 :(得分:1)
我认为ISNUMERIC函数可以解决问题。
CASE WHEN ISNUMERIC(n.x.value('DispatchedQuantity[1]', 'varchar(max)')) = 0 THEN 0 ELSE ... END
但是,我不明白为什么在将xml转换为十进制之前将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)