Лучший способ в TSQL искать xml для узла, который не существует - PullRequest
3 голосов
/ 04 января 2011

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

Ответы [ 2 ]

4 голосов
/ 04 января 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)]
2 голосов
/ 04 января 2011

Если вы просто хотите найти узлы, в которых отсутствует элемент <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.

...