SQL多行/记录到一行有3列

时间:2015-03-12 15:36:07

标签: sql sql-server-2008 tsql pivot

我有一个与这个虚拟数据类似的表,其中一个人有3条记录。我想将其更改为包含多列的一条记录。让我最困难的是我希望基于Date_Purchased的3个最新产品

现有:

NameFirst            NameLast  MbrKey      Product       DatePurchased
John                 Doe       123456      ProductA      1/1/2015 
John                 Doe       123456      ProductA      2/1/2015 
John                 Doe       123456      ProductB      3/1/2015 
John                 Doe       123456      ProductB      12/1/2015 
Joe                  Smith     987654      ProductA      3/1/2015
Jane                 Jones     555555      ProductA      1/1/2015
Jane                 Jones     555555      ProductB      1/1/2015

这是我到目前为止所做的:

select MbrKey, NameLast, NameFirst, 
Case when rn = 1 then Product else null end as Product1,
case when rn = 2 then Product else null end as Product2,
case when rn = 3 then Product else null end as Product3
from
(select t2.*
from(
select t.*, ROW_NUMBER () over (partition by t.MbrKey 
order by t.MbrKey, t.DatePurchased desc) as RN
from testing t) as t2
where t2.RN between 1 and 3) as t3 

我认为这让我更接近,因为结果如下:

NameFirst     NameLast  MbrKey      Product1     Product2     Product3 
Doe          John       123456      ProductB     NULL         NULL
Doe          John       123456      NULL         ProductA     NULL
Doe          John       123456      NULL         NULL         ProductA
Jones        Jane       555555      ProductA     NULL         NULL
Jones        Jane       555555      NULL         ProductB     NULL
Smith        Joe        987654      ProductA     NULL         NULL

未来状态:以下是我所希望的。

NameFirst     NameLast  MbrKey      Product1     Product2     Product3 
Doe           John      123456      ProductB     ProductB     ProductA
Jones         Jane      555555      ProductA     ProductB     Null
Smith         Joe       987654      ProductA     Null         Null

非常感谢任何帮助!

3 个答案:

答案 0 :(得分:2)

max()聚合函数与case语句和group by子句一起使用。您还可以跳过一定级别的子查询:

select 
  MbrKey, NameLast, NameFirst, 
  max(Case when rn = 1 then Product else null end) as Product1,
  max(case when rn = 2 then Product else null end) as Product2,
  max(case when rn = 3 then Product else null end) as Product3
from (
  select 
    t.*, 
    rn = ROW_NUMBER () over (partition by t.MbrKey order by t.MbrKey, t.DatePurchased desc)
  from testing t
) as t1 
where t1.RN between 1 and 3
group by MbrKey, NameLast, NameFirst

答案 1 :(得分:1)

你走了:

DECLARE @Table TABLE
(
    NameFirst VARCHAR(50)
    ,NameLast VARCHAR(50)
    ,MbrKey INT
    ,Product VARCHAR(50)
    ,DatePurchased DATETIME
)

INSERT INTO @Table
VALUES


('John'                 ,'Doe'       ,123456     ,'ProductA'      ,'1/1/2015' )
,('John'                ,'Doe'       ,123456     ,'ProductA'      ,'2/1/2015' )
,('John'                ,'Doe'       ,123456     ,'ProductB'      ,'3/1/2015' )
,('John'                ,'Doe'       ,123456     ,'ProductB'      ,'12/1/2015') 
,('Joe'                 ,'Smith'     ,987654     ,'ProductA'      ,'3/1/2015' )
,('Jane'                ,'Jones'     ,555555     ,'ProductA'      ,'1/1/2015' )
,('Jane'                ,'Jones'     ,555555     ,'ProductB'      ,'1/1/2015' )

SELECT 

    NameFirst 
    ,NameLast 
    ,MbrKey 
    ,MAX(CASE ProductRank WHEN 1 THEN Product END) Product1 
    ,MAX(CASE ProductRank WHEN 2 THEN Product END) Product2
    ,MAX(CASE ProductRank WHEN 3 THEN Product END) Product3

FROM 
(
    SELECT
        MbrKey
        ,MAX(NameFirst) AS NameFirst
        ,MAX(NameLast) AS NameLast
    FROM
        @Table
    GROUP BY MbrKey
) Members
CROSS APPLY
(
    SELECT TOP 3
        Product
        ,ROW_NUMBER() OVER (ORDER BY DatePurchased DESC) AS ProductRank
    FROM @Table T
    WHERE T.MbrKey = Members.MbrKey
    ORDER BY DatePurchased DESC
) Products
GROUP BY 
    Members.MbrKey
    ,Members.NameFirst
    ,Members.NameLast

编辑:在这种情况下,使用交叉应用应该比子查询方法更好地执行,因为您只需要最新的三个产品。这样,Row_Number()函数就不必对所有记录起作用。此外,如果您有成员表,则可以使用该表而不是此示例中的“成员”子查询。

答案 2 :(得分:1)

尝试PIVOT

DECLARE @t TABLE
    (
      Name NVARCHAR(MAX) ,
      Product NVARCHAR(MAX) ,
      Date DATE
    )

INSERT  INTO @t
VALUES  ( 'John', 'ProductA', '20150101' ),
        ( 'John', 'ProductA', '20150102' ),
        ( 'John', 'ProductB', '20150103' ),
        ( 'John', 'ProductB', '20150112' ),
        ( 'Joe', 'ProductA', '20150103' ),
        ( 'Jane', 'ProductA', '20150101' ),
        ( 'Jane', 'ProductB', '20150101' );


WITH    cte
          AS ( SELECT   Name ,
                        Product ,
                        ROW_NUMBER() OVER ( PARTITION BY Name ORDER BY Date DESC ) AS RN
               FROM     @t
             )
    SELECT  Name ,
            [1] AS Product1 ,
            [2] AS Product2 ,
            [3] AS Product3
    FROM    cte PIVOT( MAX(Product) FOR rn IN ( [1], [2], [3] ) ) a
    ORDER BY Name

输出:

Name    Product1    Product2    Product3
Jane    ProductA    ProductB    NULL
Joe     ProductA    NULL        NULL
John    ProductB    ProductB    ProductA

当然你应该在MbrKey分区。我留给你。