【问题标题】:SQL Server SELECT FOR XML How to get two elements at the same levelSQL Server SELECT FOR XML 如何获取同一级别的两个元素
【发布时间】:2014-05-21 16:07:23
【问题描述】:

我有两个不同的 XML 片段要放在一起。

例如,第一段的 SQL 如下所示:

SELECT
  *
FROM
  (
    SELECT 1 AS OrdNum, 'Abc'       AS Name
  ) a
FOR XML
  AUTO,
  TYPE

一旦执行,你会得到这个:

<a OrdNum="1" Name="Abc" />

第二个在这里:

SELECT
  *
FROM
  (
     SELECT 4  AS Age, 'M'  AS Sex,   'John'      AS FirstName
  ) b
FOR XML
  AUTO,
  TYPE

你会得到这个:

<b Age="4" Sex="M" FirstName="John" />

现在我将这两部分放在一起:

SELECT
  *
FROM
  (

    SELECT
      (
        SELECT
          *
        FROM
          (
            SELECT 1 AS OrdNum, 'Abc'       AS Name
          ) a
        FOR XML
          AUTO,
          TYPE
      ) AS aa

      ,

      (
        SELECT
          *
        FROM
          (
             SELECT 4  AS Age, 'M'  AS Sex,   'John'      AS FirstName
          ) b
        FOR XML
          AUTO,
          TYPE
      ) AS bb

  ) Data
FOR XML
  AUTO,
  ELEMENTS

结果如下:

<Data>
  <aa>
    <a OrdNum="1" Name="Abc" />
  </aa>
  <bb>
    <b Age="4" Sex="M" FirstName="John" />
  </bb>
</Data>

但我不想在其中包含元素“aa”和“bb”。我很想得到这个:

<Data>
  <a OrdNum="1" Name="Abc" />
  <b Age="4" Sex="M" FirstName="John" />
</Data>

但我不知道如何实现。

有什么提示吗?

【问题讨论】:

    标签: sql-server select-for-xml


    【解决方案1】:

    没有“简单”的方法可以做到这一点。 FOR XML PATH|EXPLICIT|AUTO 都要求每个顶级输出元素具有相同的名称。而且您不能将多个 FOR XML 查询合并在一起(Sql Server 2012)。

    你走的方向是最可靠、最灵活的。本质上,您必须为要包含的每种不同元素类型添加一个单独的列。你可以简化你的最终尝试来得到你想要的:

    SELECT
        (
            SELECT 1 AS [@OrdNum], 'Abc' AS [@Name]
                WHERE 1=1
                FOR XML PATH ('a'), TYPE
        )
        , 
        (
            SELECT 4 AS [@Age], 'M' AS [@Sex], 'John' AS [@FirstName]
                WHERE 1=1
                FOR XML PATH ('b'), TYPE
        )
        FOR XML PATH ('Data'), TYPE;
    

    以上查询输出:

    <Data>
      <a OrdNum="1" Name="Abc" />
      <b Age="4" Sex="M" FirstName="John" />
    </Data>
    

    当您使用FOR XML PATH 时,列别名是XPath。因此,要使其成为属性名称,您必须以'@'作为前缀---然后要求您转义别名(因此是[])。 PATH 上的参数规定了每一行的 Xml 元素的名称。 TYPE 选项表示将输出保持为 Xml 类型而不是 nvarchar(max),这意味着外部查询可以更好地合并它。外部查询只有 2 列可以填充到它所代表的单个元素中。最后,我喜欢WHERE 1=1,但它在语法上不是必需的。

    切线:我知道您的示例已简化,因此您可能希望知道 Xml 数据类型可以应用“方法”。例如,假设您想要上述内容,但外部查询只需要“b”元素。您可以使用 query() 方法仅选择部分 Xml 以合并到某些外部查询中。

    SELECT 
        (
            SELECT
                (
                    SELECT 1 AS [@OrdNum], 'Abc' AS [@Name]
                        WHERE 1=1
                        FOR XML PATH('a'), TYPE
                )
                , 
                (
                    SELECT 4 AS [@Age], 'M' AS [@Sex], 'John' AS [@FirstName]
                        WHERE 1=1
                        FOR XML PATH('b'), TYPE
                )
                FOR XML PATH('Data'), TYPE
        ).query('Data/b');
    

    产生这个:

    <b Age="4" Sex="M" FirstName="John" />
    

    【讨论】:

    • 感谢@Granger,您的答案正是我想要的。很遗憾,我的分数太低,我无法为您的回答打分。
    【解决方案2】:

    您需要查看 SQL Server 2005 引入的 FOR XML PATH 选项 - 有关详细信息,请参阅 Microsoft SQL Server 2005 文档中 FOR XML 的新增功能。

    基本上,使用 FOR XML PATH,您可以非常轻松地定义 XML 的形状。您可以定义某些结构,可以将某些列定义为属性输出,将其他列定义为元素 - 完全在您的控制之下。

    您可以在此处获取有关如何格式化的更多信息:

    enter link description here

    【讨论】:

    • 谢谢@Tanner_Gram。我也尝试了 PATH 子句,但我不确定它是否能够做到我所期望的。无论如何,谢谢你的提示。
    • 对不起,@Tanner_Gram,在我提出最初的问题时,我对您的回答不够满意。感谢下面的格兰杰,我终于明白了你的观点。再次抱歉,我既不能标记你的答案也不能标记格兰杰的答案,因为我仍然是这个论坛的“新手”,即使在我成为会员两年后:-/
    猜你喜欢
    • 1970-01-01
    • 2017-02-24
    • 2011-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-06
    • 1970-01-01
    相关资源
    最近更新 更多