SQL 多个 rows/records 成一行 3 列
SQL Multiple rows/records into one row with 3 columns
我有一个与此虚拟数据类似的 table,其中一个人有 3 条记录。我想将其更改为包含多列的一条记录。对我来说最复杂的是我想要基于 Date_Purchased
的 3 个最新产品
现有:
姓名名字姓氏 MbrKey 产品购买日期
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 产品 A 3/1/2015
简·琼斯 555555 ProductA 1/1/2015
简·琼斯 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
我认为这让我更接近了,因为结果如下:
姓名名字姓氏 MbrKey Product1 Product2 Product3
Doe John 123456 ProductB NULL NULL
Doe John 123456 NULL ProductA NULL
Doe John 123456 NULL NULL 产品A
Jones Jane 555555 ProductA NULL NULL
琼斯简 555555 NULL ProductB NULL
史密斯·乔 987654 ProductA NULL NULL
未来的状态:下面是我所希望的。
姓名名字姓氏 MbrKey Product1 Product2 Product3
Doe John 123456 产品 B 产品 B 产品 A
Jones Jane 555555 ProductA ProductB Null
史密斯·乔 987654 ProductA Null Null
如有任何帮助,我们将不胜感激!
将 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
给你:
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() 函数就不必作用于所有记录。此外,如果您有一个成员 table,您可以使用它来代替本例中的 "Members" 子查询。
尝试 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
分区。我留给你。
我有一个与此虚拟数据类似的 table,其中一个人有 3 条记录。我想将其更改为包含多列的一条记录。对我来说最复杂的是我想要基于 Date_Purchased
的 3 个最新产品现有:
姓名名字姓氏 MbrKey 产品购买日期 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 产品 A 3/1/2015 简·琼斯 555555 ProductA 1/1/2015 简·琼斯 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
我认为这让我更接近了,因为结果如下:
姓名名字姓氏 MbrKey Product1 Product2 Product3 Doe John 123456 ProductB NULL NULL Doe John 123456 NULL ProductA NULL Doe John 123456 NULL NULL 产品A Jones Jane 555555 ProductA NULL NULL 琼斯简 555555 NULL ProductB NULL 史密斯·乔 987654 ProductA NULL NULL
未来的状态:下面是我所希望的。
姓名名字姓氏 MbrKey Product1 Product2 Product3 Doe John 123456 产品 B 产品 B 产品 A Jones Jane 555555 ProductA ProductB Null 史密斯·乔 987654 ProductA Null Null
如有任何帮助,我们将不胜感激!
将 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
给你:
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() 函数就不必作用于所有记录。此外,如果您有一个成员 table,您可以使用它来代替本例中的 "Members" 子查询。
尝试 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
分区。我留给你。