How to build an HTML table with subtotals using a recursive string concatenation?

六眼飞鱼酱① 提交于 2019-12-04 11:44:58

Luckily in this case, we can simply swap out your subquery for a join and select the value directly:

DECLARE @tableBody NVARCHAR(MAX), @lastBrand VARCHAR(10), @lastTotal decimal(10,2);
SELECT @tableBody='';

SELECT
  @tableBody
    = @tableBody
      + CASE
          WHEN @lastBrand IS NOT NULL AND @lastBrand<>SS.Brand
            THEN '<tr><td colspan="2">Subtotal</td><td>'
                 + CAST(@lastTotal AS VARCHAR(15)) -- Add the last total
                 + '</td></tr>'
            ELSE '' END
      + '<tr><td>' + SS.Brand + '</td><td>'
      + SS.StoreName + '</td><td>' + CAST(SS.Sales AS VARCHAR(15)) + '</td></tr>',
  @lastBrand = SS.Brand,
  @lastTotal = SB.TotalSales -- Save the last total, too
FROM #SalesByStore SS
    join #SalesByBrand SB on SS.Brand = SB.Brand -- Join to get brand totals
ORDER BY SS.Brand

-- Finally add the last total
SELECT
  @tableBody
    = @tableBody
      + '<tr><td colspan="2">Subtotal</td><td>'
      + CAST(@lastTotal AS VARCHAR(15))
      + '</td></tr>'

You've certainly come up with a clever method of creating this HTML table. Note that I've moved things around a little and hacked together a solution.

I tested with this set of data:

insert into #SalesByStore select 'A', 'Store 1', 1000
insert into #SalesByStore select 'A', 'Store 2', 2000
insert into #SalesByStore select 'B', 'Store 3', 1500
insert into #SalesByStore select 'B', 'Store 4', 2100
insert into #SalesByStore select 'B', 'Store 5', 3100
insert into #SalesByBrand select 'A', 3000
insert into #SalesByBrand select 'B', 6700

Alternative using GROUPING SETS and proper ordering. The strings are joined together using XML PATH.

Working SQL Fiddle
The top query in the fiddle shows the variable content after the query. The bottom query just shows you what GROUPING SETS produces.

declare @tablebody nvarchar(max) = '';
select @tablebody = (select 
  case
  when storename is null then
   '<tr><td colspan="2">Subtotal</td>
        <td>'+cast(sum(sales) as varchar(15))+'</td></tr>'
 else
   '<tr><td>'+brand+'</td>
        <td>'+storename+'</td>
        <td>'+cast(sum(sales) as varchar(15))+'</td></tr>'
  end
from salesbystore
group by grouping sets
((brand, storename),(brand))
order by brand, case when storename is null then 1 else 0 end
for xml path (''), root('a'), type
).value('(/a)[1]','nvarchar(max)');
select @tablebody;

While grouping is certainly a feature of SQL Server 2008 onwards and should replace all usage of WITH ROLLUP, this particular example can easily be switch to a WITH ROLLUP for SQL Server 2005 using 3 lines replacing the 2 shown

group by brand, storename  -- group by grouping sets
with rollup                -- ((brand, storename),(brand))
having brand is not null
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!