Como filtrar um campo de XML em várias condições
-
21-12-2019 - |
Pergunta
Eu tenho uma tabela como tal:
CREATE TABLE MyTable(
Id [int] IDENTITY(1,1) NOT NULL,
XmlField xml NULL,
/// Some other fields
)
O campo de XML contém uma representação XML de um C# Dictionary<int, string>
.E. g :
<dictionary>
<item>
<key><int>1</int></key>
<value><string>Web</string></value>
</item>
<item>
<key><int>2</int></key>
<value><string>Email</string></value>
</item>
// more item
</dictionary>
O que eu quero fazer é selecionar todas as linhas onde XmlField contém (chave = 1 valor = 'Web') e também contém (chave = 2 valor = 'e-Mail').
Até agora eu só consegui linhas de filtro para 1 única chave/valor correspondência:
SELECT TableId, XmlField FROM MyTable
CROSS APPLY XmlField.nodes('/dictionary/item') x(fields)
WHERE (x.fields.value('(key/int/text())[1]', 'int') = 1
AND x.fields.value('(value/string/text())[1]', 'varchar(MAX)') = 'Web')
Se eu adicionar AND (x.fields.value('(key/int/text())[1]', 'int') = 2 AND x.fields.value('(value/string/text())[1]', 'varchar(MAX)') = 'Email')
então, nada é devolvido (muito logicamente).
Eu também tentei não usar CROSS APPLY
e fazer um filtro simples tais como:
SELECT TableId, XmlField FROM MyTable
WHERE XmlField.exist('/dictionary/item/key/int[text() = 1]') = 1
AND XmlField.exist('/dictionary/item/value/string[text() = "Web"]') = 1
Mas, em seguida, ele age como um OR
e gostaria de retornar linhas onde o xml contém 2 pares de valor-chave, tais como (1, de e-Mail) e (2, Web).
Solução
Algo como isso deve fazê-lo.
select *
from MyTable as T
where T.XmlField.exist('/dictionary[item[key/int/text() = 1 and value/string/text() = "Web"] and
item[key/int/text() = 2 and value/string/text() = "Email"]]') = 1