我需要将Rows数据转换为特定条件下的列。假设我们在2015年那么它需要将下一年的数据作为新列获取。请看一下表A,有人建议我如何达到预期的结果?
表A:
EmpID Year Price Cm St1 St2
03 2015 1 AB 1 0
03 2016 2 CD 0 1
04 2016 2 XY 0 1
04 2015 20 ZX 0 1
预期产出:
EmpID Year Y1_Price Y1_Cm Y1_St1 Y1_St2 Y2_Price Y2_Cm Y2_St1 Y2_St2
03 2015 1 AB 1 0 2 CD 0 1
03 2016 2 CD 0 1 NULL NULL NULL NULL
04 2016 2 XY 0 1 NULL NULL NULL NULL
04 2015 20 ZX 0 1 2 XY 0 1
请帮我编写以下场景的SQL
答案 0 :(得分:3)
请把事情复杂化。我花了大约10分钟来编写这个查询,这很容易实现。
@Sandeep - 使用下面的脚本,它将为您提供您正在寻找的内容。假设Test是你的表名。
查询:
WITH CTE AS
(
SELECT EmpId, Year, Price, Cm, St1, St2, ROW_NUMBER() OVER(PARTITION BY EmpId ORDER BY Year) RNo
FROM TEST
)
SELECT T1.EmpId, T1.Year
, T1.Price Y1_Price, T1.Cm Y1_Cm, T1.St1 Y1_St1, T1.St2 Y1_St2
, T2.Price Y2_Price, T2.Cm Y2_Cm, T2.St1 Y2_St1, T2.St2 Y2_St2
FROM CTE T1
LEFT JOIN CTE T2 ON T1.EmpId = T2.EmpId AND T1.RNo + 1 = T2.RNo
答案 1 :(得分:2)
假设您正在进行年度比较
Declare @Table table (EmpID varchar(25),Year int,Price money,CM varchar(25), St1 int,St2 int)
Insert into @Table (EmpID,Year,Price,Cm,St1,St2) values
('03',2015,1,'AB',1,0),
('03',2016,2,'CD', 0,1),
('04',2016,2,'XY',0,1),
('04',2015,20,'ZX',0,1)
Select A.EmpID
,A.Year
,Y1_Price = A.Price
,Y1_CM = A.CM
,Y1_St1 = A.ST1
,Y1_St2 = A.ST2
,Y2_Price = B.Price
,Y2_CM = B.CM
,Y2_St1 = B.ST1
,Y2_St2 = B.ST2
From @Table A
Left Join @Table B on (A.EmpID = B.EmpID and A.Year+1=B.Year)
返回
EmpID Year Y1_Price Y1_CM Y1_St1 Y1_St2 Y2_Price Y2_CM Y2_St1 Y2_St2
03 2015 1.00 AB 1 0 2.00 CD 0 1
03 2016 2.00 CD 0 1 NULL NULL NULL NULL
04 2016 2.00 XY 0 1 NULL NULL NULL NULL
04 2015 20.00 ZX 0 1 2.00 XY 0 1
答案 2 :(得分:1)
好的,下面是我编写的一个查询示例,它可以执行类似于您想要的操作。它需要一组数据并根据起始年份动态调整。我只给你第一个支点(价格)。如果要在第二列及以后的列上进行透视,则需要创建第二个动态选择字符串,然后再在动态SQL中的新数据透视表上进行连接。
declare @startYear int = 2010;
declare @startDate datetime = '1/1/2010 00:00:00.000';
declare @endYear int = year(getutcdate());
declare @endDate datetime = convert(datetime, '12/31/' + convert(nvarchar, @endYear) + ' 23:59:59.997');
-- our variables for string concatenation
declare @yearString nvarchar(max) = ''
, @piv1YearSelectionString nvarchar(max) = ''
, @query nvarchar(max) = ''
;
-- check for the existence of our temp table and dropping it
if exists (
select * from tempdb.dbo.sysobjects o
where o.xtype in ('U')
and o.id = object_id(N'tempdb..#rawData')
)
begin
drop table #rawData;
end
-- create our temp table
create table #rawData
(
EmployeeId nvarchar(50)
, InvoiceYear int
, Price money
, Cm nvarchar(50)
, St1 int
, St2 int
);
-- concatenate our strings with our year column names
while (@startYear <= @endYear)
begin
-- creates a string of values like [2010, 2011, ...]
set @yearString = @yearString + '[' + convert(nvarchar, @startYear) + ']';
-- creates a string of values like ['COALESCE(MAX[a].[2011], 0) as [Price2011], ...
set @piv1YearSelectionString = @piv1YearSelectionString + 'COALESCE(MAX([a].[' + convert(nvarchar, @startYear) + ']), 0) AS [Price' + convert(nvarchar, @startYear) + ']';
set @startYear = @startYear + 1;
-- adds commas to the strings
if @startYear <= @endYear
begin
set @yearString = @yearString + ', ';
set @piv1YearSelectionString = @piv1YearSelectionString + ', ';
end
end
;
-- build the query here
set @query = '
declare @sDate datetime = ''' + convert(varchar, @startDate) + ''';
declare @eDate datetime = dateadd(s, -1, dateadd(yyyy, 1, @sDate));
declare @stopDate datetime = ''' + convert(varchar, @endDate) + ''';
while @sDate < @stopDate
begin
-- uncomment the line below to see the dates
--select @sDate, @eDate;
-- collect your input table
insert #rawData ( employeeId, invoiceYear, Price, Cm, St1, St2 )
select
EmployeID
, year(InvoiceDate) as InvoiceYear
, Price
, Cm
, St1
, St2
from
<SourceQuery>
where
InvoiceDate between @sdate and @eDate
;
set @sDate = dateadd(yyyy, 1, @sDate);
set @eDate = dateadd(ms, -1, dateadd(yyyy, 1, @sDate));
end
-- dynamically pivot
select
a.EmployeeId
, ' + @piv1YearSelectionString + '
from
(
select
piv1.CompanyId, piv1.CompanyName, ' + @yearString + '
from
#rawData
pivot
(
max(Price)
for [invoiceYear] in (' + @yearString + ')
) as piv1
) a
group by
a.EmployeeId
order by
a.EmployeeId
';
-- run the query
execute(@query);
-- clean up
drop table #rawdata;