これは、HTML を手動で作成する非常に醜い方法です。これが SQL Server に属さないのには十分な理由があります。XML の第一人者がやってきて、もっと簡単な方法で私を当惑させることは間違いありません (私はSimon Sabin のソリューションを試してみましたが、それをあなたの要件に変換することはできませんでした)。
DECLARE @x TABLE(Gender VARCHAR(6), Age INT, Name VARCHAR(32));
INSERT @x VALUES ('Male', 30, 'Bill'), ('Female', 27, 'Jenny'),
('Female', 27, 'Debby'), ('Male', 44, 'Frank');
DECLARE @html NVARCHAR(MAX) = N'';
;WITH x AS ( SELECT x.Age, x.Gender, x.Name,
dr = DENSE_RANK() OVER (PARTITION BY x.Gender ORDER BY x.Age),
gn = ROW_NUMBER() OVER (PARTITION BY x.Gender ORDER BY x.Age),
rn = ROW_NUMBER() OVER (ORDER BY x.Gender DESC, x.Age)
FROM @x AS x ) SELECT @html +=
CHAR(13) + CHAR(10) + CASE WHEN c1.gn = 1 THEN
CASE WHEN c1.rn > 1 THEN '</li></ul></li></ul>' ELSE '' END + '<ul><li>'
+ c1.Gender ELSE '' END + CHAR(13) + CHAR(10) + CHAR(9)
+ CASE WHEN c1.gn = 1 OR c1.Age <> c3.Age THEN
CASE WHEN c1.gn > 1 THEN '</li>' ELSE '<ul>' END + '<li>'
+ CONVERT(VARCHAR(32), c1.Age) ELSE '' END + CHAR(13) + CHAR(10) + CHAR(9)
+ CHAR(9) + CASE WHEN (c1.gn = 1 OR c1.Age <> c3.Age) THEN '<ul>' ELSE '' END
+ '<li>' + c1.Name + '</li>' + CASE WHEN c1.Age <> c2.Age OR c1.dr <> c2.dr
THEN '</ul>' ELSE '' END
FROM x AS c1
LEFT OUTER JOIN x AS c2
ON c1.rn = c2.rn - 1
LEFT OUTER JOIN x AS c3
ON c1.rn = c3.rn + 1
ORDER BY c1.Gender DESC, c1.Age;
SELECT @html += '</ul></li></ul></li></ul>';
PRINT @html; -- note you will need to deal with this
-- in another way if the string is large
結果 - 空白に関して要求したものとは正確には異なりますが、同一の HTML レンダリング:
<ul><li>Male
<ul><li>30
<ul><li>Bill</li></ul>
</li><li>44
<ul><li>Frank</li></ul>
</li></ul></li></ul><ul><li>Female
<ul><li>27
<ul><li>Jenny</li>
<li>Debby</li></ul></li></ul></li></ul>
EDITよりクリーンなソリューション、および多くのドラマと、@ ZeeTeeがStackOverflowで最も迷惑なユーザーである理由の良いデモンストレーションについては、フォローアップの質問に対するMikaelのソリューションを参照してください。
Select ステートメントをフォーマットされた HTML として返す (SQL 2005)