根据没有 PIVOT 的列将所有列转置为行

Transpose all columns to rows based on a column without PIVOT

我正在处理一个报表,其中所有列都需要根据列转置为行。

CREATE TABLE TempTable(
  Company VARCHAR(5), 
  ProcessDate DATETIME, 
  OpExp DECIMAL, 
  Tax DECIMAL, 
  Total DECIMAL);

INSERT INTO TempTable VALUES
('Comp1', getdate(), 1000, 100, 1100),
('Comp1', dateadd(year, -1, getdate()), 2000, 200, 2200),
('Comp1', dateadd(year, -2, getdate()), 3000, 300, 3300);

SELECT * FROM TempTable;

但是为了报告,我必须将这个 table 转换成

这里的 2015、2016、2017 列是动态的,基于 'ProcessDate' 年。

我尝试使用 PIVOT,但它抛出

Incorrect syntax near 'PIVOT'. You may need to set the compatibility level of the current database to a higher value to enable this feature. See help for the SET COMPATIBILITY_LEVEL option of ALTER DATABASE

由于数据库已经在生产中,因此无法更改 兼容级别。

我按照

中的建议尝试使用 UNION ALL, CASE

Simple way to transpose columns and rows in Sql?

但列数据类型不同,不能使用聚合函数,因为结果必须包含所有行。

有什么方法可以将列转换为行吗?或者是否可以使用 SSRS 而不是 RDLC 生成此报告?

注意:您或许可以更改兼容级别。只要您将兼容性级别更改为更高的值并且您没有依赖此数据库处于该特定版本的链接服务器等,它就不会影响任何事情。显然,如果您不确定,请不要触摸它

无论如何,有几种方法可以做到这一点。此方法使用 UNION,我不确定您为什么说不能使用此方法,但这正是您的样本期望。

DECLARE @Temptable TABLE (
  Company VARCHAR(5), 
  ProcessDate DATETIME, 
  OpExp DECIMAL, 
  Tax DECIMAL, 
  Total DECIMAL);

INSERT INTO @TempTable VALUES
('Comp1', getdate(), 1000, 100, 1100),
('Comp1', dateadd(year, -1, getdate()), 2000, 200, 2200),
('Comp1', dateadd(year, -2, getdate()), 3000, 300, 3300);

SELECT * FROM @TempTable

DECLARE @ReportStartYear int = 2017

SELECT 
    t.Company
    , 'OpExp' as Val
    , SUM(CASE YEAR(t.ProcessDate) WHEN @ReportStartYear -2 THEN OpExp ELSE 0 END) AS ColA
    , SUM(CASE YEAR(t.ProcessDate) WHEN @ReportStartYear -1 THEN OpExp ELSE 0 END) AS ColB
    , SUM(CASE YEAR(t.ProcessDate) WHEN @ReportStartYear  THEN OpExp ELSE 0 END) AS ColC
    , @ReportStartYear - 2 as ColACaption
    , @ReportStartYear - 1 as ColBCaption
    , @ReportStartYear  as ColCCaption
    FROM @Temptable t
    GROUP BY t.Company
UNION ALL
SELECT 
    t.Company
    , 'Tax' as Val
    , SUM(CASE YEAR(t.ProcessDate) WHEN @ReportStartYear -2 THEN Tax ELSE 0 END) AS ColA
    , SUM(CASE YEAR(t.ProcessDate) WHEN @ReportStartYear -1 THEN Tax ELSE 0 END) AS ColB
    , SUM(CASE YEAR(t.ProcessDate) WHEN @ReportStartYear  THEN Tax ELSE 0 END) AS ColC
    , @ReportStartYear - 2 as ColACaption
    , @ReportStartYear - 1 as ColBCaption
    , @ReportStartYear  as ColCCaption
    FROM @Temptable t
    GROUP BY t.Company
UNION ALL
SELECT 
    t.Company
    , 'Total' as Val
    , SUM(CASE YEAR(t.ProcessDate) WHEN @ReportStartYear -2 THEN Total ELSE 0 END) AS ColA
    , SUM(CASE YEAR(t.ProcessDate) WHEN @ReportStartYear -1 THEN Total ELSE 0 END) AS ColB
    , SUM(CASE YEAR(t.ProcessDate) WHEN @ReportStartYear  THEN Total ELSE 0 END) AS ColC
    , @ReportStartYear - 2 as ColACaption
    , @ReportStartYear - 1 as ColBCaption
    , @ReportStartYear  as ColCCaption
    FROM @Temptable t
    GROUP BY t.Company

这个return下面

Company Val     ColA    ColB    ColC    ColACaption ColBCaption ColCCaption
Comp1   OpExp   3000    2000    1000    2015        2016        2017
Comp1   Tax     300     200     100     2015        2016        2017
Comp1   Total   3300    2200    1100    2015        2016        2017

在您的报告中,您可以将列 headers 设置为 =FIRST(Fields!ColACaption.Value) 等,这样您就不必担心列名称是动态的。 如果您知道要 return.

的列数,则此方法有效

HOWEVER 如果在 SSRS 中执行此操作可能更容易。创建一个矩阵,将列组设置为 return 是 ProcessDate 列的 YEAR 的表达式,然后在详细信息组中为每个值类型(OpExp、Tax 和 Total)添加一行,并且应该给你你想要的也不需要改变任何 SQL.

这是 SSRS 的唯一方法,这可能是最好的方法...

我在这个例子中稍微扩展了你的样本数据,包括 9 行,3 行 3 家公司。

创建一个新的空白报告并照常添加您的数据集。 然后在报表上插入一个矩阵控件。 如下图所示拖动字段以初始设置矩阵。我们将对其进行编辑,但它可以让我们快速入门。

注意: 第 3 步应为 "Drag ProcessDate here..."

现在我们需要将流程日期更改为年份,因此 right-click 步骤 3 中的 ProcessDate 单元格并单击 'expression'。将表达式设置为

=YEAR(Fields!ProcessDate.Value)

在组设计器窗格中的报表设计下,right-click 在 [ProcessDate] 列组上并选择 'group properties' 并将 Group On 属性 设置为相同的表达式=YEAR(Fields!ProcessDate.Value)

现在回到报表设计中,right-click 数据单元格(来自上面的第 4 步)并执行 'Insert Row' -> 'Inside Group - Below'

重复此过程以添加第 3 行。

在两个新的空白单元格中,单击字段列表下拉菜单并分别选择“税收”和“总计”。

如果要添加标题栏。 Right-click 包含 [Company] 的单元格,执行 'Insert Column' -> 'Inside Group - Right',然后右键单击新单元格并选择 'split cell' 这将取消合并 3 行。然后您可以为每一行键入标题。 设计现在应该如下所示。

就是这样..

最终输出如下所示。