我在这个网站上搜索了所有可能的解决方案,但仍无法找到我的Pivot问题的答案。
我有一张包含以下数据的表格。
Portfolio | Date | TotalLoans | ActiveLoans | TotalBalance
--------------------------------------------------------------------
P1 | 2015-12-31 | 1,000 | 900 | 100,000.00
P1 | 2015-11-30 | 1,100 | 800 | 100,100.00
P1 | 2015-10-31 | 1,200 | 700 | 100,200.00
我正在尝试使用以下输出创建一个轴(仅限于Portfolio = P1)
Field | 2015-12-31 | 2015-11-30 | 2015-10-31 |
-----------------------------------------------------
TotalLoans | 1,000 | 1,100 | 1,200 |
ActiveLoans | 900 | 800 | 700 |
TotalBalance | 100,000 | 100,100 | 100,200 |
理想情况下,我正在寻找动态数据透视表,但静态查询也可以,我可以尝试使用动态查询。
答案 0 :(得分:3)
首先需要UNPIVOT
你的桌子。您可以使用此查询执行此操作:
SELECT Portfolio, [Date], Val, ColType
FROM (SELECT Portfolio,
[Date],
TotalLoans,
ActiveLoans,
TotalBalance
FROM mytable
WHERE Portfolio = 'P1') AS srcUnpivot
UNPIVOT (
Val FOR ColType IN (TotalLoans, ActiveLoans, TotalBalance)) AS unpvt
<强>输出:强>
Portfolio Date Val ColType
===============================================
P1 2015-12-31 1000 TotalLoans
P1 2015-12-31 900 ActiveLoans
P1 2015-12-31 100000 TotalBalance
P1 2015-11-30 1100 TotalLoans
P1 2015-11-30 800 ActiveLoans
P1 2015-11-30 100100 TotalBalance
P1 2015-10-31 1200 TotalLoans
P1 2015-10-31 700 ActiveLoans
P1 2015-10-31 100200 TotalBalance
注意: 所有不透明字段必须属于相同类型。上面的查询假定所有字段的类型为 int 。如果不是这种情况,则必须使用CAST
。
使用上述查询,您可以应用PIVOT
:
SELECT Portfolio, ColType, [2015-12-31], [2015-11-30], [2015-10-31]
FROM (
... above query here ...
PIVOT (
MAX(Val) FOR [Date] IN ([2015-12-31], [2015-11-30], [2015-10-31])) AS pvt
答案 1 :(得分:3)
这是Giorgos Betsos解决方案的动态SQL。这将在不需要明确写日期值的情况下进行处理。
请:如果你喜欢这个:不要将此解决方案标记为已接受,请将接受设置为Giorgos Betsos。这是艰苦的工作!但你可以投票: - )
CREATE TABLE #tbl(Portfolio VARCHAR(10),[Date] DATE,TotalLoans DECIMAL(10,4),ActiveLoans DECIMAL(10,4),TotalBalance DECIMAL(10,4));
INSERT INTO #tbl VALUES
('P1','20151231',1000,900,100000.00)
,('P1','20151130',1100,800,100100.00)
,('P1','20151031',1200,700,100200.00);
DECLARE @pvtColumns VARCHAR(MAX)=
(
STUFF(
(
SELECT DISTINCT ',['+CONVERT(VARCHAR(10), [Date] ,126) + ']'
FROM #tbl
FOR XML PATH('')
)
,1,1,'')
);
DECLARE @cmd VARCHAR(MAX)=
'SELECT Portfolio, ColType, ' + @pvtColumns +
' FROM (
SELECT Portfolio, [Date], Val, ColType
FROM (SELECT Portfolio,
[Date],
TotalLoans,
CAST(ActiveLoans AS DECIMAL(10,4)) AS ActiveLoans,
TotalBalance
FROM #tbl AS mytable
WHERE Portfolio = ''P1'') AS srcUnpivot
UNPIVOT (
Val FOR ColType IN (TotalLoans, ActiveLoans, TotalBalance)) AS unpvt
) AS srcPivot
PIVOT (
MAX(Val) FOR [Date] IN (' + @pvtColumns + ')) AS pvt';
EXEC (@cmd);
答案 2 :(得分:1)
您需要使用Dyanmic SQL并构建它们。请参阅http://social.technet.microsoft.com/wiki/contents/articles/17510.t-sql-dynamic-pivot-on-multiple-columns.aspx
上的示例这是代码
CREATE procedure CrossTab
(
@select varchar(2000),
@PivotCol varchar(100),
@Summaries varchar(100),
@GroupBy varchar(100),
@OtherCols varchar(100) = Null
)
AS
set nocount on
set ansi_warnings off
declare @sql varchar(8000)
Select @sql = ''
Select @OtherCols= isNull(', ' + @OtherCols,'')
create table #pivot_columns (pivot_column_name varchar(100))
Select @sql='select ''' + replace( + @PivotCol,',',''' as pivot_column_name union all select ''')+''''
insert into #pivot_columns
exec(@sql)
select @sql=''
create table #pivot_columns_data (pivot_column_name varchar(100),pivot_column_data varchar(100))
Select @PivotCol=''
Select @PivotCol=min(pivot_column_name) from #pivot_columns
While @PivotCol>''
Begin
insert into #pivot_columns_data(pivot_column_name,pivot_column_data)
exec
(
'select distinct ''' + @PivotCol +''' as pivot_column_name, convert(varchar(100),' + @PivotCol + ') as pivot_column_data from
('+
@select
+'
) T'
)
Select @PivotCol=min(pivot_column_name) from #pivot_columns where pivot_column_name>@PivotCol
end
select
@sql = @sql + ', ' +
replace(
replace(
@Summaries,'(','(CASE WHEN ' + Pivot_Column_name + '=''' +
pivot_column_data + ''' THEN '
),
')[', ' END) as [' + pivot_column_data
)
from #pivot_columns_data
order by pivot_column_name
exec
(
'select ' + @GroupBy +@OtherCols +@sql +
' from (
'+
@select
+'
) T
GROUP BY ' + @GroupBy
)
drop table #pivot_columns
drop table #pivot_columns_data
set nocount off
set ansi_warnings on
用法
EXEC CrossTab
'SELECT LastName, OrderDate,shipcountry FROM northwind..Employees Employees
INNER JOIN northwind..Orders Orders ON (Employees.EmployeeID=Orders.EmployeeID) ',
'shipcountry,Year(OrderDate)',
'Count(LastName)[]',
'LastName'
答案 3 :(得分:1)
分几步完成:
if object_id('tempdb..#Data') is null
CREATE TABLE #Data
([Portfolio] varchar(2), [Date] datetime,
[TotalLoans] decimal(9,2), [ActiveLoans] int, [TotalBalance] decimal(9,2))
;
INSERT INTO #Data
([Portfolio], [Date], [TotalLoans], [ActiveLoans], [TotalBalance])
VALUES
('P1', '2015-12-31', 1000, 900, 100000.00),
('P1', '2015-11-30', 1100, 800, 100100.00),
('P2', '2015-10-31', 1200, 700, 100200.00)
;
WITH Transposed AS (
--First reorganise the data, creating unions like this, by column
--Assumption is that you are not interested in [Portfolio]
SELECT [Portfolio], [Date], [TotalLoans] AS Amount, 'TotalLoans' Field FROM #Data
UNION SELECT [Portfolio], [Date], [ActiveLoans], 'ActiveLoans' FROM #Data
UNION SELECT [Portfolio], [Date], [TotalBalance], 'TotalBalance' FROM #Data
)
SELECT Field, [2015-10-31], [2015-11-30], [2015-12-31] --You can build a string with all the dates from your original data source
FROM (
SELECT [Date], [Field], [Amount] FROM Transposed
) d
PIVOT (
MAX(Amount)
FOR [Date] IN ([2015-10-31], [2015-11-30], [2015-12-31])
) p