这与作为 XML 元素的 SQL 数据非常相似——以至于我认为它可能是重复的——但我想为你的上下文解释一下为什么这不是最好的主意。在我对这个问题的回答中,我展示了一种非常老套的方法,你可以做到这一点,但这不是最好的主意。
您的 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,就像我在其他答案中一样。