patternsqlModerate
Return xml sequences where an attribute doesn't contain a specific character
Viewed 0 times
returncontainwherecharacterxmldoesnattributespecificsequences
Problem
Consider the following simple XML:
I want to get a list of `
I want to get a list of `
sequences where the address attribute of the item does not contain an @.
So, I want output that looks like:
mcve:
DECLARE @x XML = '
';
This query:
SELECT WithValidEmail = @x.query('/xml/customer/email[contains(@address, "@")]')
, WithInvalidEmail = @x.query('/xml/customer/email[contains(@address, "@")] = False');
Returns:
╔═══════════════════════════════════════╦══════════════════╗
║ WithValidEmail ║ WithInvalidEmail ║
╠═══════════════════════════════════════╬══════════════════╣
║ ║ ║
║ ║ false ║
╚═══════════════════════════════════════╩══════════════════╝
This query:
SELECT WithInValidEmail = @x.query('/xml/customer/email')
WHERE @x.exist('/xml/customer/email[contains(@address, "@")]') = 0;
Returns:
╔══════════════════╗
║ WithInValidEmail ║
╚══════════════════╝
(no results)
The WHERE` clause in the query above is eliminating the entire set of XML because at least a single sequence exists where the email address contains an "@" sign.Solution
An easy way to do this is to use the
The problem with the way you're looking now is that it's only checking that any email address has an
If you need to query an actual table with an XML column like this, you'd just
If you want to bring all the
Another way of doing it is:
Moving the square brackets to wrap around the email node effectively make that the
Get me all
which does not contain the
nodes method to get right to the address attribute and check for your @ sign.The problem with the way you're looking now is that it's only checking that any email address has an
@ in it. Parsing the XML nodes out lets you check individual emails for it.DECLARE @x XML
= '
';
SELECT x.c.value('@address', 'VARCHAR(100)') AS [email]
FROM @x.nodes('/xml/customer/email') AS x(c)
WHERE x.c.exist('@address[contains(., "@")]') = 0;If you need to query an actual table with an XML column like this, you'd just
CROSS APPLY the nodes method like thusly:SELECT x.c.value('@address', 'VARCHAR(100)') AS [email]
FROM @x_table AS xt
CROSS APPLY xt.x.nodes('/xml/customer/email') AS x(c)
WHERE x.c.exist('@address[contains(., "@")]') = 0;If you want to bring all the
... XML for that "row" back, you can walk the axis back. Just be aware that walking back can make performance a bit woogy for large XML blocks.SELECT x.c.query('..')
FROM @x_table AS xt
CROSS APPLY xt.x.nodes('/xml/customer/email') AS x(c)
WHERE x.c.exist('@address[contains(., "@")]') = 0;Another way of doing it is:
SELECT @x.query('/xml/customer[email/@address[not(contains(., "@"))]]') answerMoving the square brackets to wrap around the email node effectively make that the
WHERE clause applied to the customer node. Translating this XQuery to English looks like:Get me all
xml/customer nodes with an email node which has an address attributewhich does not contain the
@ symbolCode Snippets
DECLARE @x XML
= '<xml>
<customer name="Max"><email address="me@you.com" /></customer>
<customer name="Erik"><email address="erik@your-mom.com" /></customer>
<customer name="Brent"><email address="brentcom" /></customer>
</xml>';
SELECT x.c.value('@address', 'VARCHAR(100)') AS [email]
FROM @x.nodes('/xml/customer/email') AS x(c)
WHERE x.c.exist('@address[contains(., "@")]') = 0;SELECT x.c.value('@address', 'VARCHAR(100)') AS [email]
FROM @x_table AS xt
CROSS APPLY xt.x.nodes('/xml/customer/email') AS x(c)
WHERE x.c.exist('@address[contains(., "@")]') = 0;SELECT x.c.query('..')
FROM @x_table AS xt
CROSS APPLY xt.x.nodes('/xml/customer/email') AS x(c)
WHERE x.c.exist('@address[contains(., "@")]') = 0;SELECT @x.query('/xml/customer[email/@address[not(contains(., "@"))]]') answerContext
StackExchange Database Administrators Q#204920, answer score: 11
Revisions (0)
No revisions yet.