【问题标题】:SQL query for Dynamic nodes in XML [duplicate]XML中动态节点的SQL查询[重复]
【发布时间】:2017-03-09 13:49:56
【问题描述】:

我们的桌子是这样的

StudentNo  Name  Subject  Mark   Grade
1          John   English  41     A
1          John   Hindi    42     B 

我们希望这个表中的 XML 格式如下。

<Student>
    <Name>John</Name>
  <Subject>
    <English>
          <Mark>41</Mark>
          <Grade>A</Grade>
    </English>
    <Hindi>
          <Mark>42</Mark>
          <Grade>B</Grade>
    </Hindi>
 </Subject>
<Student>

这里的主题名称节点应该是动态生成的。

【问题讨论】:

    标签: sql sql-server xml for-xml-path select-for-xml


    【解决方案1】:

    这与SQL Data as XML Element 非常相似——以至于我认为它可能是重复的——但我想根据您的上下文进一步解释一下为什么这不是最好的主意。在我对这个问题的回答中,我展示了一种非常老套的方法,你可以这样做,但这不是最好的主意。

    几乎不可能为您的 XML 创建架构。该 XML 的任何使用者将永远无法确定哪些值可能作为元素出现。与其尝试创建动态元素,不如使用某种属性。您甚至可以使用xsi:type 在您的各种XML 中创建一个抽象类型(尽管在我的示例中我只是使用一个普通的旧属性——您可以选择对您的消费者最有意义的任何属性)。该 XML 的查询将是:

    declare @subjects TABLE(studentno int, name varchar(10), subjecT varchar(10), mark int, grade char(1))
    
    INSERT @subjects
    VALUES
    (1, 'John','English',  41,'A'),
    (1, 'John','Hindi',    42,'B')
    
    select 
        s.Name
    
        ,(SELECT
            s2.Subject as '@type'
            ,s2.Mark
            ,s2.Grade
        FROM @subjects s2 
        WHERE s2.studentno = s.studentno
        FOR XML PATH('Subject'), ROOT('Subjects'), TYPE)
    from @subjects s
    GROUP BY s.name, s.studentno
    FOR XML PATH('Student')
    

    产生:

    <Student>
      <Name>John</Name>
      <Subjects>
        <Subject type="English">
          <Mark>41</Mark>
          <Grade>A</Grade>
        </Subject>
        <Subject type="Hindi">
          <Mark>42</Mark>
          <Grade>B</Grade>
        </Subject>
      </Subjects>
    </Student>
    

    消费者可以理解此 XML,例如,他们可以在不知道可能存在哪些主题的情况下迭代主题(并且无需假设Subjects 的每个直接子代都在实际上是一个主题,而不是在新版本的架构中添加的其他类型的节点)。


    如果您真的需要该输出,我更愿意使用 XSLT 将上面的输出转换为您的格式,例如:

    <?xml version="1.0" encoding="UTF-8" ?>
    <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
        <xsl:output method="xml" encoding="UTF-8" indent="yes" />
    
        <xsl:template match="node()|@*">
         <xsl:copy>
             <xsl:apply-templates />
         </xsl:copy>
        </xsl:template>
    
        <xsl:template match="Subject">
            <xsl:element name="{@type}">
                <xsl:apply-templates />
            </xsl:element>
        </xsl:template>
    
        <xsl:template match="Subjects">
            <xsl:element name="Subject">
                <xsl:apply-templates />
            </xsl:element>
        </xsl:template>
    </xsl:transform>
    

    得到你

    <?xml version="1.0" encoding="UTF-8"?>
    <Student>
      <Name>John</Name>
      <Subject>
          <English>
             <Mark>41</Mark>
             <Grade>A</Grade>
          </English>
          <Hindi>
             <Mark>42</Mark>
             <Grade>B</Grade>
          </Hindi>
      </Subject>
    </Student>
    

    请注意,您不能完全使用 SQL Server 做到这一点 - 您必须求助于构建 XML 字符串并将其转换为 XML,就像在我的其他答案中一样。

    【讨论】:

    • 但是我们需要以下格式的 XMLJohn41A42B
    • 在这种情况下,我将创建一个 XSLT 样式表来处理来自 SQL 的内容 - 看看我的其他答案,使用 SQL Server 是可能的,但它变得非常丑陋。您必须手动创建一个 XML 字符串并将其转换为 XML - FOR XML 构造都不支持您正在尝试执行的操作。
    • 我添加了一个可以转换它的 XSLT 示例。
    • 这是一个有深刻见解的好答案!
    猜你喜欢
    • 1970-01-01
    • 2022-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-03
    • 1970-01-01
    • 2018-10-18
    • 2022-12-06
    相关资源
    最近更新 更多