Лучший способ в TSQL искать в xml несуществующий узел

У нас есть исходный 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, и это работает, но я не совсем уверен, что так должно быть. Я пробовал несколько вариантов с функцией .exist, но не смог получить правильный результат.


person epic_fil    schedule 03.01.2011    source источник


Ответы (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

Он использует встроенный метод .exist() в XQuery для проверки существования подузла внутри узла XML.

person marc_s    schedule 03.01.2011

Если вы просто хотите убедиться, что выбираете address элементы с элементом zip_code, настройте XPATH, чтобы включить эти критерии в фильтр предикатов:

/addresses/address[zip_code]

Если вы также хотите убедиться, что элемент zip_code также имеет значение, используйте фильтр предикатов для zip_node, чтобы выбрать те, которые имеют text() узлов:

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

РЕДАКТИРОВАТЬ:

Собственно, ищу обратное. Мне нужно идентифицировать узлы, у которых нет zip, чтобы мы могли вручную исправить исходные данные.

Итак, если вы хотите идентифицировать все элементы address, которые не имеют zip_code, вы можете указать его в XPATH следующим образом:

/addresses/address[not(zip_code)]
person Mads Hansen    schedule 04.01.2011
comment
Собственно, ищу обратное. Мне нужно идентифицировать узлы, у которых нет zip, чтобы мы могли вручную исправить исходные данные. - person epic_fil; 10.01.2011
comment
Извините, я неправильно понял. Я обновил пример того, как можно адресовать только элементы address, у которых нет zip_code. - person Mads Hansen; 10.01.2011