这似乎是一件很简单的事情,但我不确定我是否正确地考虑它以获得理想的结果。我正在使用一个支点,但我认为我需要一些与之配对的东西。
我有一张发票表,其中包含每个客户的月度发票。最多,客户每年将有12张发票,每月1张。
+----------+-------+-------+--------------+--------------+--------------+
| ClientID | Month | Year | ColumnValue1 | ColumnValue2 | ColumnValue3 |
+----------+-------+-------+--------------+--------------+--------------+
| 1 | 1 | 2012 | 20 | 30 | 50 |
| 1 | 2 | 2012 | 25 | 35 | 40 |
| 2 | 1 | 2012 | 28 | 38 | 48 |
+----------+-------+-------+--------------+--------------+--------------+
现在,我想根据每个客户端创建一个如下所示的列表。每个月都会有一个专栏。所以客户端1看起来像:
+--------------+----+----+---+---+---+---+---+---+---+----+----+----+-------+
| ColumnName | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Total |
+--------------+----+----+---+---+---+---+---+---+---+----+----+----+-------+
| ColumnValue1 | 20 | 25 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 45 |
| ColumnValue2 | 30 | 35 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 65 |
| ColumnValue3 | 50 | 40 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 90 |
+--------------+----+----+---+---+---+---+---+---+---+----+----+----+-------+
答案 0 :(得分:4)
这可以使用SQL Server中的UNPIVOT
和PIVOT
函数来完成。如果您有已知数量的列,则可以使用静态版本:
select clientid,
col, year,
isnull([1], 0) [1],
isnull([2], 0) [2],
isnull([3], 0) [3],
isnull([4], 0) [4],
isnull([5], 0) [5],
isnull([6], 0) [6],
isnull([7], 0) [7],
isnull([8], 0) [8],
isnull([9], 0) [9],
isnull([10], 0) [10],
isnull([11], 0) [11],
isnull([12], 0) [12],
(isnull([1], 0) + isnull([2], 0) + isnull([3], 0)
+ isnull([4], 0) + isnull([5], 0) + isnull([6], 0)
+ isnull([7], 0) + isnull([8], 0) + isnull([9], 0)
+ isnull([10], 0) + isnull([11], 0) + isnull([12], 0) ) Total
from
(
select clientid, col, month, year, value
from yourtable
unpivot
(
value for col in (ColumnValue1, ColumnValue2, ColumnValue3)
) u
) x
pivot
(
sum(value)
for month in ([1], [2], [3], [4], [5], [6], [7],
[8], [9], [10], [11], [12])
) p
但是使用动态sql执行此操作可能要容易得多,然后编写的代码就会减少,这将根据数据样本中的内容调整月数:
DECLARE @colsUnpivot AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX),
@colsPivot as NVARCHAR(MAX),
@colsTotal as NVARCHAR(MAX),
@colsNull as NVARCHAR(MAX)
select @colsUnpivot = stuff((select ','+ quotename(C.name)
from sys.columns as C
where C.object_id = object_id('yourtable') and
C.name like 'ColumnValue%'
for xml path('')), 1, 1, '')
select @colsPivot = STUFF((SELECT distinct ', ' + quotename(Month)
from yourtable t
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select @colsNull = STUFF((SELECT distinct ', IsNull('
+ quotename(Month) + ', 0) as '+quotename(Month)
from yourtable t
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select @colsTotal = STUFF((SELECT distinct '+ IsNull('
+ quotename(Month) + ', 0)'
from yourtable t
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query
= 'select clientid,
year,
'+@colsNull+', '+@colsTotal+' as Total
from
(
select clientid, col, month, year, value
from yourtable
unpivot
(
value for col in ('+@colsUnpivot+')
) u
) x
pivot
(
sum(value)
for month in('+ @colspivot +')
) p'
exec(@query)
两者都会产生相同的结果,区别在于第二个会根据表格中的数据进行调整:
| CLIENTID | YEAR | 1 | 2 | TOTAL |
-------------------------------------
| 1 | 2012 | 20 | 25 | 45 |
| 1 | 2012 | 30 | 35 | 65 |
| 1 | 2012 | 50 | 40 | 90 |
| 2 | 2012 | 28 | 0 | 28 |
| 2 | 2012 | 38 | 0 | 38 |
| 2 | 2012 | 48 | 0 | 48 |
答案 1 :(得分:3)
试试这个
Declare @t Table(ClientId Int,[Month] Int,[Year] Int,ColumnValue1 Int,ColumnValue2 Int, ColumnValue3 Int)
Insert Into @t Values(1,1,2012,20,30,50),(1,2,3012,25,35,40),(2,1,2012,28,38,48)
;With Cte As
(
Select ClientId,[Month],ColumnName,ColumnNameValues
From @t
UnPivot(ColumnNameValues For ColumnName In (ColumnValue1,ColumnValue2,ColumnValue3)) As unpvt
)
Select ClientId,
ColumnName
,[1] = Coalesce([1],0)
,[2] = Coalesce([2],0)
,[3] = Coalesce([3],0)
,[4] = Coalesce([4],0)
,[5] = Coalesce([5],0)
,[6] = Coalesce([6],0)
,[7] = Coalesce([7],0)
,[8] = Coalesce([8],0)
,[9] = Coalesce([9],0)
,[10]= Coalesce([10],0)
,[11]= Coalesce([11],0)
,[12] = Coalesce([12],0)
,Total = Coalesce([1],0) + Coalesce([2],0) + Coalesce([3],0) + Coalesce([4],0) +
Coalesce([5],0) + Coalesce([6],0) + Coalesce([7],0) + Coalesce([8],0) +
Coalesce([9],0) + Coalesce([10],0) + Coalesce([11],0) + Coalesce([12],0)
From Cte
PIVOT
(
MAX(ColumnNameValues) For [Month] In ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12] )
) As pvt
--Where ClientId =1 -- uncomment for specific client report
Order By 1
<强>结果强>
答案 2 :(得分:2)
Create table sequence (seqid bigint)
go
--Create a table which has sequence from 1 to 12 for monthId
Insert into sequence
Select Top 12 ROW_NUMBER() over(order by name)
from sys.objects
go
USE tempdb
GO
CREATE TABLE TestReport
(
ClientId int
,MonthId int
,YearId int
,val1 int
,val2 int
,val3 int
)
go
insert into TestReport
Select 1, 1,2012, 20,30,50
union
Select 1,2,2012,25, 35, 40
union
Select 2, 1, 2012, 28,38,48
Select *
from testReport
--Cross join with the Sequence table to get rows for each month
Select clientId
, seqid as monthId
, YearId
, case when MonthId = seqid then val1 else 0 end val1
, case when MonthId = seqid then val2 else 0 end val2
, case when MonthId = seqid then val3 else 0 end val3
into #Temp
from sequence seq
cross join testReport rpt
where seq.seqid <=12
--Select * from #Temp
SELECT 'ColumnValue1' AS [columnName], [1], [2], [3], [4],[5],[6],[7],[8],[9],[10],[11],[12]
,[1]+ [2]+ [3]+ [4]+ [5]+ [6]+ [7]+ [8]+ [9]+ [10]+ [11]+ [12] as Total
FROM
(SELECT monthId, val1
FROM #Temp
where ClientId =1
) AS SourceTable
PIVOT
(
max(val1) FOR MonthId IN ( [1], [2], [3], [4],[5],[6],[7],[8],[9],[10],[11],[12])
)
AS PivotTable
go
Drop table #Temp
Drop table sequence
drop table TestReport
go