FOR XML in SQL 服务器:基于列公共值的元素

FOR XML in SQL Server: Elements based on common values of columns

我正在使用 FOR XML 从 SQL 查询中创建一个 XML 文件。我希望元素基于特定列的公共值,在本例中为 "location":

location    team    score
Adelong     SFP     104
Adelong     LIB     189
Adelong     CDP     9
Hurstville  SFP     14
Hurstville  LIB     64
Hurstville  CDP     13

我可以像这样轻松地将他的逐行转换为 XML:

SELECT(SELECT location, team, score FROM MyTable FOR XML PATH('node'), TYPE ) FOR XML PATH(''), ROOT('root')

产生的 XML 看起来像这样:

  <node>
    <location>Adelong</location>
    <team>SFP</team>
    <score>104</score>
  </node>
  <node>
    <location>Adelong</location>
    <team>LIB</team>
    <score>189</score>
  </node>
  <node>
    <location>Adelong</location>
    <team>CDP</team>
    <score>9</score>
  </node>

但我真正想要的是:

<location name="Adelong">
    <node>
        <team>SFP</team>
        <score>104</score>
    </node>
    <node>
        <team>LIB</team>
        <score>189</score>
    </node>
    <node>
        <team>CDP</team>
        <score>9</score>
    </node>
</location>

您可以使用临时派生的 table 来获取不同的位置,select 从中获取位置并在相关子查询中获取球队和分数。

SELECT t1.location [@name],
       (SELECT t2.team,
               t2.score
               FROM mytable t2
               WHERE t2.location = t1.location
               FOR XML PATH('node'),
                       TYPE)
       FROM (SELECT DISTINCT
                    t1.location
                    FROM mytable t1) t1
       FOR XML PATH('location');

db<>fiddle

这是基于 XQuery FLWOR 表达式的解决方案。

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, [location] VARCHAR(20), team CHAR(3), score INT);
INSERT INTO @tbl (location, team, score)
VALUES
('Adelong'     ,'SFP',  104)
,('Adelong'    ,'LIB',  189)
,('Adelong'    ,'CDP',  9  )
,('Hurstville' ,'SFP',  14 )
,('Hurstville' ,'LIB',  64 )
,('Hurstville' ,'CDP',  13 );
-- DDL and sample data population, end

SELECT (
    SELECT *
    FROM @tbl
    FOR XML PATH('r'), TYPE, ROOT('root')).query('<root>
{
   for $x in distinct-values(/root/r/location)
   return <location name="{$x}">
   {
        for $y in /root/r[location/text() = $x]
        return <node>
            {$y/team}
            {$y/score}
        </node> 
    }
    </location>
}
</root>');