问题
I have a data set that looks something like this:
Gender | Age | Name
Male | 30 | Bill
Female | 27 | Jenny
Female | 27 | Debby
Male | 44 | Frank
And I'm trying to display this as specially formatted HTML code:
<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>
I tried using FOR XML but that didn't give the results I was looking for. It didn't remove the multiple Gender and Age fields returned. As you can see in this HTML it is compounding it all and only giving duplicates at the end node.
Aaron Bertrand provided an excellent method here Return Select Statement as formatted HTML that seems to work perfectly in SQL 2008, but I was looking for something that worked in 2005 as well, besides the little stuff, like += operators and setting default DECLARE values, just doesn't display in 2005.
How would something like this be achieved in SQL Server 2005?
回答1:
declare @T table
(
Gender varchar(10),
Age int,
Name varchar(10)
)
insert into @T values ('Male', 30, 'Bill')
insert into @T values ('Female', 27, 'Jenny')
insert into @T values ('Female', 27, 'Debby')
insert into @T values ('Male', 44, 'Frank')
select Gender as 'li',
(select T2.Age as 'li',
(select T3.Name as 'li'
from @T as T3
where T2.Age = T3.Age and
T1.Gender = T3.Gender
for xml path(''), root('ul'), type) as 'li'
from @T as T2
where T1.Gender = T2.Gender
group by T2.Age
for xml path(''), root('ul'), type) as 'li'
from @T as T1
group by Gender
for xml path('ul')
回答2:
Here is the code for SQL Server 2005, which only required minor adjustments from the answer I gave yesterday which was requested for SQL Server 2008 specifically:
DECLARE @x TABLE(Gender VARCHAR(6), Age INT, Name VARCHAR(32));
INSERT @x SELECT 'Male', 30, 'Bill' UNION ALL SELECT 'Female', 27, 'Jenny'
UNION ALL SELECT 'Female', 27, 'Debby' UNION ALL SELECT 'Male', 44, 'Frank';
DECLARE @html NVARCHAR(MAX);
SET @html = 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 = @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 = @html + '</ul></li></ul></li></ul>';
PRINT @html; -- note you will need to deal with this
-- in another way if the string is large
And here is proof that it works:
回答3:
SET ANSI_WARNINGS ON;
DECLARE @Test TABLE
(
Gender VARCHAR(10) NOT NULL,
Age INT NOT NULL,
Name VARCHAR(50) NOT NULL
);
INSERT @Test (Gender, Age, Name)
SELECT 'Male' ,30 ,'Bill'
UNION ALL
SELECT 'Female',27 ,'Jenny'
UNION ALL
SELECT 'Female',27 ,'Debby'
UNION ALL
SELECT 'Male' ,44 ,'Frank';
DECLARE @x XML;
SET @x =
(
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;
Refences: SQL Server XQuery
来源:https://stackoverflow.com/questions/10300764/return-select-statement-as-formatted-html-sql-2005