SQL Server XML列中的部分通配符搜索

时间:2016-06-27 13:54:49

标签: sql-server xml xpath xquery-sql

我在MS SQL Server 2012数据库中有一个XML列,我需要创建一个查询,将节点提取到表中。以下是XML结构的要点:

<root>
  <ProjectInfo>
  <PrimaryContact>
    <Name>
    <Phone>
    <Email>
  </PrimaryContact>
  <SecondaryContact>
    <Name>
    <Phone>
    <Email>
  </SecondaryContact>
  <TechnicalContact>
    <Name>
    <Phone>
    <Email>
  </TechnicalContact>
  <BillingContact>
    <Name>
    <Phone>
    <Email>
  </BillingContact>
  <OtherStuff>
</root>

我正在尝试编写一个查询,从每个Contact节点获取Name,Phone和Email。遗憾的是,XPath /root/*Contact/不合法。我知道我可以编写一个结合了大量UNION s的查询来合并列,但我觉得可能有一种我目前不知道的更简单的方法。

有没有办法使用通配符或某种OR-ing机制,可用于检索名称,电话和&amp;来自每个* Contact节点的电子邮件?

注意:我无法使用/root/*/Name,因为还有其他节点将Name作为下一个内部节点,而不是联系人,而Phone&amp;电子邮件都是可选字段。

1 个答案:

答案 0 :(得分:1)

您可以查看此工作示例:

DECLARE @xml XML=
'<root>
  <ProjectInfo>
    <Name value="this not"/>
  </ProjectInfo>
  <PrimaryContact>
    <Name value="x"/>
    <Phone value="y"/>
    <Email value="z"/>
  </PrimaryContact>
  <SecondaryContact>
    <Name value="a"/>
    <Phone value="b"/>
    <Email value="c"/>
  </SecondaryContact>
  <TechnicalContact>
    <Name value="e"/>
    <Phone value="f"/>
    <Email value="g"/>
  </TechnicalContact>
  <BillingContact>
    <Name value="m"/>
    <Phone value="n"/>
    <Email value="o"/>
  </BillingContact>
  <OtherStuff>
    <Name value="don''t include"/>
  </OtherStuff>
</root>';

SELECT Level1.value('local-name(.)','nvarchar(max)') AS Level1_Name
      ,Level2.value('local-name(.)','nvarchar(max)') AS Level2_Name
      ,Level2.value('@value','nvarchar(max)') AS Level2_Value
FROM @xml.nodes('/root/*[fn:contains(local-name(),"Contact")]') A(Level1)
CROSS APPLY Level1.nodes('*') AS B(Level2);

结果

+------------------+-------+---+
| PrimaryContact   | Name  | x |
+------------------+-------+---+
| PrimaryContact   | Phone | y |
+------------------+-------+---+
| PrimaryContact   | Email | z |
+------------------+-------+---+
| SecondaryContact | Name  | a |
+------------------+-------+---+
| SecondaryContact | Phone | b |
+------------------+-------+---+
| SecondaryContact | Email | c |
+------------------+-------+---+
| TechnicalContact | Name  | e |
+------------------+-------+---+
| TechnicalContact | Phone | f |
+------------------+-------+---+
| TechnicalContact | Email | g |
+------------------+-------+---+
| BillingContact   | Name  | m |
+------------------+-------+---+
| BillingContact   | Phone | n |
+------------------+-------+---+
| BillingContact   | Email | o |
+------------------+-------+---+

只需删除[fn:contains(local-name(),"Contact")],您就会看到ProjectInfoOtherStuff的名称 - 值。

如果您需要并排使用列,则可以使用PIVOT

SELECT p.*
FROM
(
    SELECT Level1.value('local-name(.)','nvarchar(max)') AS Level1_Name
          ,Level2.value('local-name(.)','nvarchar(max)') AS Level2_Name
          ,Level2.value('@value','nvarchar(max)') AS Level2_Value
    FROM @xml.nodes('/root/*[fn:contains(local-name(),"Contact")]') A(Level1)
    CROSS APPLY Level1.nodes('*') AS B(Level2)
) AS tbl
PIVOT
(
    MIN(Level2_Value) FOR Level2_Name IN(Name,Phone,Email)
) AS p;

结果:

+------------------+------+-------+-------+
| Level1_Name      | Name | Phone | Email |
+------------------+------+-------+-------+
| BillingContact   | m    | n     | o     |
+------------------+------+-------+-------+
| PrimaryContact   | x    | y     | z     |
+------------------+------+-------+-------+
| SecondaryContact | a    | b     | c     |
+------------------+------+-------+-------+
| TechnicalContact | e    | f     | g     |
+------------------+------+-------+-------+