3

我有接下来的两张桌子:

CREATE TABLE #SalesByStore (
    Brand VARCHAR(10),
    StoreName VARCHAR(50),
    Sales DECIMAL(10,2)
)

CREATE TABLE #SalesByBrand (
    Brand VARCHAR(10),
    TotalSales DECIMAL(10,2)
)

我正在尝试使用递归字符串连接构建一个 HTML 表体,我需要按品牌排序的商店显示销售额,并且在同一品牌的每组商店显示该品牌的销售额小计之后,如下所示:

在此处输入图像描述

我正在按照以下方式进行操作:

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

SELECT
  @tableBody
    = @tableBody
      + CASE
          WHEN @lastBrand IS NOT NULL AND @lastBrand<>SS.Brand
            THEN '<tr><td colspan="2">Subtotal</td><td>'
                 + (SELECT TOP 1 CAST(SB.TotalSales AS VARCHAR(15)) FROM #SalesByBrand SB WHERE SB.Brand=@lastBrand)
                 + '</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
FROM #SalesByStore SS
ORDER BY SS.Brand

问题是按品牌获取小计金额的子查询始终返回 NULL,因为子查询的@lastBrand 仍然为空(请参阅此堆栈溢出问题以了解为什么会发生这种情况:Why subquery inside recursive string连接总是返回 NULL?)。

您能否建议我另一种在 SQL Server 2005 中创建带有小计的 HTML 表的方法?

顺便说一句,我需要在 SQL Server 中构建 HTML 表,以便在 db 邮件中发送它。

编辑:我已将案例从连接的结尾移至连接的开头,因为必须在新品牌组开始之前绘制小计行。对不起这个错误。

4

2 回答 2

3

幸运的是,在这种情况下,我们可以简单地将子查询换成连接并直接选择值:

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>'

您肯定想出了一个巧妙的方法来创建这个 HTML 表格。请注意,我已经移动了一些东西并一起破解了一个解决方案。

我用这组数据进行了测试:

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
于 2012-10-04T16:04:31.507 回答
2

使用 GROUPING SETS 和正确排序的替代方法。这些字符串使用 XML PATH 连接在一起。

工作SQL Fiddle 小提琴
中的顶部查询显示了查询后的变量内容。底部查询只是向您显示 GROUPING SETS 产生的内容。

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;

虽然分组肯定是 SQL Server 2008 以后的一个特性,并且应该替换所有使用 WITH ROLLUP,但这个特定示例可以很容易地切换到 SQL Server 2005 的 WITH ROLLUP,使用 3 行替换所示的 2

group by brand, storename  -- group by grouping sets
with rollup                -- ((brand, storename),(brand))
having brand is not null
于 2012-10-04T20:25:44.127 回答