在TSQL中搜索xml以寻找不存在的节点的更好方法

时间:2011-01-03 22:24:18

标签: sql xml tsql sql-server-2008-r2 xquery

我们有一个源XML文件,其中包含address个节点,并且每个节点都应该在下面有一个zip_code节点才能进行验证。我们收到了一个未通过架构验证的文件,因为至少有一个节点缺少它的zip_code(文件中有几千个地址)。

我们需要找到没有邮政编码的元素,这样我们就可以修复文件并将审核报告发送给源。

--declare @x xml = bulkcolumn from openrowset(bulk 'x:\file.xml',single_blob) as s
declare @x xml = N'<addresses>
    <address><external_address_id>1</external_address_id><zip_code>53207</zip_code></address>
    <address><external_address_id>2</external_address_id></address>
</addresses>'

declare @t xml = (
select @x.query('for $a in .//address 
    return 
        if ($a/zip_code) 
            then <external_address_id /> 
        else $a/external_address_id')
)
select x.AddressID.value('.', 'int') AddressID
from @t.nodes('./external_address_id') x(AddressID)
where x.AddressID.value('.', 'int') > 0
GO

真的,这是where条款让我烦恼。我觉得我依赖于对null 0的{​​{1}}值的演员表,但它确实有效,但我不确定它应该如此。我尝试了.exist函数的一些变体,但是我无法得到正确的结果。

2 个答案:

答案 0 :(得分:4)

如果您只是想确保选择具有address元素的zip_code元素,请调整XPATH以在谓词过滤器中包含该条件:

/addresses/address[zip_code]

如果您还想确保zip_code元素也有值,请使用zip_node的谓词过滤器来选择具有text()个节点的谓词过滤器:

/addresses/address[zip_code[text()]]

修改

  

实际上,我正在寻找   相反。我需要识别节点   没有拉链,所以我们可以   手动更正源数据。

因此,如果您要识别具有address的所有zip_code元素,您可以在XPATH中指定它,如下所示:

/addresses/address[not(zip_code)]

答案 1 :(得分:2)

如果您只想找到缺少<zip_code>元素的节点,可以使用以下内容:

SELECT
    ADRS.ADR.value('(external_address_id)[1]', 'int') as 'ExtAdrID'
FROM
    @x.nodes('/addresses/address') as ADRS(ADR)
WHERE
    ADRS.ADR.exist('zip_code') = 0

它使用XQuery中的内置.exist()方法来检查XML节点内是否存在子节点。