SQL 服务器中的行到列(可能是数据透视表)

Rows into Columns In SQL Server (May be Pivot)

我需要在特定条件下将行数据转换为列。假设我们在 2015 年,那么它需要将明年的数据作为新列获取。请查看 Table A,有人可以建议我怎样才能达到预期的结果吗?

Table答:


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

好的,下面是我编写的查询示例,它执行与您想要的类似的操作。它需要一组数据并根据起始年份动态调整。我只给了你第一个支点(价格)。当您想在第二列及以后的列上进行透视时,您需要创建第二个动态 select 字符串,然后在动态 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;

假设您正在进行年度比较

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)

Returns

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

请把事情复杂化。我花了大约 10 分钟来编写此查询,实现起来非常容易。

@Sandeep - 使用下面的脚本,它将为您提供您正在寻找的内容。假设 Test 是您的 table 姓名。

查询:

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