返回属性不包含特定字符的 xml 序列

Han*_*non 10 xml sql-server xquery

考虑以下简单的 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>
Run Code Online (Sandbox Code Playgroud)

我想要得到的名单<Customer>,其中序列address中的属性<email>项并没有包含@

所以,我希望输出看起来像:

<customer name="Brent">
  <email address="brentcom" />
</customer>
Run Code Online (Sandbox Code Playgroud)

麦克维

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>';
Run Code Online (Sandbox Code Playgroud)

这个查询:

SELECT WithValidEmail = @x.query('/xml/customer/email[contains(@address, "@")]')
    , WithInvalidEmail = @x.query('/xml/customer/email[contains(@address, "@")] = False');
Run Code Online (Sandbox Code Playgroud)

返回:

????????????????????????????????????????????????????????????
?            WithValidEmail             ? WithInvalidEmail ?
????????????????????????????????????????????????????????????
? <email address="me@you.com" />        ?                  ?
? <email address="erik@your-mom.com" /> ? false            ?
????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

这个查询:

SELECT WithInValidEmail = @x.query('/xml/customer/email')
WHERE @x.exist('/xml/customer/email[contains(@address, "@")]') = 0;
Run Code Online (Sandbox Code Playgroud)

返回:

????????????????????
? WithInValidEmail ?
????????????????????
    (no results)
Run Code Online (Sandbox Code Playgroud)

WHERE上面查询中的子句消除了整个 XML 集,因为至少存在一个序列,其中电子邮件地址包含“@”符号。

Eri*_*ing 11

执行此操作的一种简单方法是使用该nodes 方法获取address属性并检查您的@符号。

您现在查看方式的问题在于,它只是检查任何电子邮件地址中是否包含@。解析 XML 节点可以让您检查单个电子邮件。

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;
Run Code Online (Sandbox Code Playgroud)

如果您需要使用这样的 XML 列查询实际表,您只需CROSS APPLY像这样使用 nodes 方法:

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;
Run Code Online (Sandbox Code Playgroud)

如果您想<customer>...</customer>返回该“行”的所有XML,您可以返回轴。请注意,后退可能会使大型 XML 块的性能变得有些糟糕。

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;
Run Code Online (Sandbox Code Playgroud)

另一种方法是:

SELECT @x.query('/xml/customer[email/@address[not(contains(., "@"))]]') answer
Run Code Online (Sandbox Code Playgroud)

移动方括号以环绕电子邮件节点有效地使该WHERE子句应用于customer节点。将此 XQuery 翻译成英语看起来像:

获取具有不包含符号的属性xml/customeremail节点的所有节点address@