我的挑战是:
这是我到目前为止的代码:
PIVOT
(SUM([Revenue])
FOR [Year Month] IN ([201710], [201711])
) AS Pivot1
PIVOT
(SUM([Gross Profit])
FOR [Year Month] IN ([201710], [201711])
) AS Pivot2
答案 0 :(得分:2)
SQL语言具有非常严格的要求,您可以预先知道每列的数量和类型。查询优化器/数据库引擎需要这样做,以便构建有效的执行计划并评估查询中使用的列的权限。即使使用SELECT *
也符合此要求,因为查询其余部分中使用的任何给定表或视图中的列数是固定且已知的(至少在该查询的生命周期内)。
您要求的是要求结果中的列数由数据确定,直到创建执行计划之后才知道。这是不允许的。实现这一目标的唯一方法是通过动态SQL,您可以在其中执行三个步骤。首先运行SELECT以获取您需要的列。然后使用该数据动态构建新的查询字符串。最后,执行刚刚构建的查询字符串并将数据返回给用户。
答案 1 :(得分:0)
通常没有动态SQL,你没有很多选项。你需要在SELECT col as alias
中使用别名。
在Oracle中,您可以使用以下方法获得更好的结果:
SELECT *
FROM source
PIVOT (SUM(Revenue) AS Revenue, SUM(Profit) AS Profit
FOR (YearMonth) IN (201801, 201802)) s;
<强> DBFiddle Demo 强>
答案 2 :(得分:0)
你想获得以下回报吗? 我不明白你的目标,为什么201802年的B收入在201801收入中回归。
if object_id('tempdb..#t') is not null drop table #t
go
create table #t(Customer varchar(100),[Date] varchar(100),Revenue int,Profit int)
insert into #t(Customer,[Date],Revenue,Profit)
select 'a','201801',100,1 union all
select 'a','201801',10,11 union all
select 'b','201802',200,20
declare @sql nvarchar(max),@cols nvarchar(max)
select @cols=isnull(@cols+',','')+quotename('Revenue '+[Date])+','+quotename('Profit '+[Date]) from #t group by [date]
set @sql='
select * from (
select customer,colname,colvalue
from #t
cross apply(values(''Revenue ''+[Date],Revenue),(''Profit ''+[Date],Profit)) c(colName,ColValue)
) as t pivot (sum(colvalue) for colname in ('+@cols+')) p'
exec(@sql)
+----------+----------------+---------------+----------------+---------------+ | customer | Revenue 201801 | Profit 201801 | Revenue 201802 | Profit 201802 | +----------+----------------+---------------+----------------+---------------+ | a | 110 | 12 | NULL | NULL | | b | NULL | NULL | 200 | 20 | +----------+----------------+---------------+----------------+---------------+