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

在TSQL中搜索xml以查找不存在的节点的更好方法,sql,xml,tsql,sql-server-2008-r2,xquery,Sql,Xml,Tsql,Sql Server 2008 R2,Xquery,我们有一个具有地址节点的源XML文件,每个节点下面都应该有一个邮政编码节点,以便进行验证。我们收到一个未能通过架构验证的文件,因为至少有一个节点缺少其邮政编码。该文件中有数千个地址 我们需要找到没有邮政编码的元素,以便修复文件并向源代码发送审计报告 --declare @x xml = bulkcolumn from openrowset(bulk 'x:\file.xml',single_blob) as s declare @x xml = N'<addresses> &

我们有一个具有地址节点的源XML文件,每个节点下面都应该有一个邮政编码节点,以便进行验证。我们收到一个未能通过架构验证的文件,因为至少有一个节点缺少其邮政编码。该文件中有数千个地址

我们需要找到没有邮政编码的元素,以便修复文件并向源代码发送审计报告

--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子句让我烦透了。我觉得我依赖于将空值转换为0,这是可行的,但我不确定它是否应该。我尝试了.exist函数的一些变体,但无法得到正确的结果。

如果您只想查找缺少元素的节点,可以使用以下方法:

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
/addresses/address[not(zip_code)]

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

如果您只是想确保选择的地址元素具有邮政编码元素,请调整XPATH以将该条件包括在谓词筛选器中:

/addresses/address[zip_code]
如果还希望确保zip_代码元素也有值,请使用zip_节点的谓词过滤器来选择那些具有文本节点的元素:

编辑:

事实上,我在找 对面的我需要识别节点 那没有拉链,所以我们可以 手动更正源数据

因此,如果要标识所有没有邮政编码的地址元素,可以在XPATH中指定它,如下所示:

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
/addresses/address[not(zip_code)]

事实上,我正在寻找相反的答案。我需要识别没有zip的节点,以便手动更正源数据。对不起,我误解了。我更新了一个示例,说明了如何只处理没有邮政编码的地址元素。