我的数据集看起来像这样:
Gender | Age | Name
Male | 30 | Bill
Female | 27 | Jenny
Female | 27 | Debby
Male | 44 | Frank
我正在尝试将其显示为特殊格式的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>
我尝试使用FOR XML
但是没有给出我想要的结果。它没有删除返回的多个Gender
和Age
字段。正如你在这个HTML中看到的那样,它正在复合它,只在末端节点上提供重复。
在SQL Server中如何实现这样的目标?
答案 0 :(得分:5)
这是一种非常难看的手动制作HTML的方法。有一个很好的理由不属于SQL Server。我肯定会有一些XML专家出现并用一种更直接的方法使我难堪(我使用Simon Sabin's solution但无法将其转换为您的要求),但是现在:
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>
编辑为了更清晰的解决方案,以及大量的戏剧性和很好的演示,为什么@ZeeTee是StackOverflow上最烦人的用户,请参阅Mikael对后续问题的解决方案:
答案 1 :(得分:0)
注意:我已将for $g in ("Male", "Female")
替换为for $g in distinct-values(//root
/row/@Gender)
。
注意:2 我删除了每个性别的重复年龄(演示here)。
此外,这可以使用XQueries来完成:
DECLARE @x XML =
(
SELECT *
FROM @Test t
FOR XML RAW, ROOT
);
SELECT @x AS [Source];
SELECT @x.query('
for $g in distinct-values(//root/row/@Gender) (: or for $g in ("Male", "Female") :)
return
<ul>
<li>
{data($g)}
<ul>
{
for $a in distinct-values(//root/row[@Gender=$g]/@Age)
return <li>{data($a)}
<ul>
{
for $n in //root/row
where $n/@Gender=$g and $n/@Age = $a
return <li>{data($n/@Name)}</li>
}</ul></li>
}
</ul>
</li>
</ul>
') AS Result;
结果:
Source
----------------------------------------------------
<root>
<row Gender="Male" Age="30" Name="Bill" />
<row Gender="Female" Age="27" Name="Jenny" />
<row Gender="Female" Age="27" Name="Debby" />
<row Gender="Male" Age="44" Name="Frank" />
</root>
Result
----------------------------------------------------
<ul><li>Female<ul><li>27<ul><li>Jenny</li><li>Debby</li></ul></li></ul></li></ul>
<ul><li>Male<ul><li>30<ul><li>Bill</li></ul></li><li>44<ul><li>Frank</li></ul></li></ul></li></ul>