Reputation: 381
First of all - I have been looking at examples for two days and have tried applying them but have not been successful. I do not understand the mechanics of how Pivot works and I would appreciate some help.
I have a dataset with multiple rows per Customer - one row per purchase. I want to get one row per customer - with up to 6 purchases and the purchase date for each.
Honestly, I don't even know if this is possible ... as the Purchase Dates [PDate] can vary so widely. ?
Here is SQL for my starting Dataset:
DECLARE @Test AS TABLE
(
Location VARCHAR(20),
Mgr VARCHAR(30),
CId VARCHAR(20),
CName VARCHAR(100),
BDate DATE,
Age Int,
Item Varchar(15),
PDate Date
)
Insert Into @Test
(Location, Mgr, CId, CName, BDate, Age, Item, PDate)
Values
('A','Bob','1','Bill Jones','1967-04-27', 50,'Hammer','2017-04-05'),
('A','Bob','1','Bill Jones','1967-04-27', 50,'Nails','2017-03-17'),
('A','Bob','1','Bill Jones','1967-04-27', 50,'Screws','2017-02-15'),
('A','Bob','1','Bill Jones','1967-04-27', 50,'Nails','2017-01-26'),
('A','Bob','1','Bill Jones','1967-04-27', 50,'Screws','2016-12-20'),
('A','Bob','1','Bill Jones','1967-04-27', 50,'Nails','2016-11-03'),
('B','Dan','15','Sharon Jones','1969-04-27', 48,'Nails','2017-04-05'),
('B','Dan','15','Sharon Jones','1969-04-27', 48,'Nails','2017-03-07'),
('B','Dan','15','Sharon Jones','1969-04-27', 48,'Screws','2017-02-18')
Select * From @Test
I need to see this:
A Bob 1 Bill Jones 1967-04-27 50 Hammer 2017-04-05 Nails 2017-03-17 ....
B Dan 15 Sharon Jones 1969-04-27 48 Nails 2017-04-05 Nails 2017-03-07 ....
... essentially, one row for each CId with: Location, Mgr, CId, CName, BDate, Age, Item1, Date1, Item2, Date2, Item3, Date3 ... up to 6 purchased items.
Thanks in advance!
Upvotes: 3
Views: 285
Reputation: 82010
Since you don't need to go dynamic and maxing out at 6, a simple conditional aggregation would do.
Select Location, Mgr, CId, CName, BDate, Age
,[Item1] = max(case when RN=1 then Item end)
,[Date1] = max(case when RN=1 then Pdate end)
,[Item2] = max(case when RN=2 then Item end)
,[Date2] = max(case when RN=2 then Pdate end)
,[Item3] = max(case when RN=3 then Item end)
,[Date3] = max(case when RN=3 then Pdate end)
,[Item4] = max(case when RN=4 then Item end)
,[Date4] = max(case when RN=4 then Pdate end)
,[Item5] = max(case when RN=5 then Item end)
,[Date5] = max(case when RN=5 then Pdate end)
,[Item6] = max(case when RN=6 then Item end)
,[Date6] = max(case when RN=6 then Pdate end)
From (
Select *
,RN = Row_Number() over (Partition By Location, Mgr, CId, CName, BDate, Age Order by Item,PDate)
From Test
) A
Group By Location, Mgr, CId, CName, BDate, Age
As Requested - Some Commentary
This is a simple conditional aggregation with a little twist. The twist is the sub-query using a window function Row_Number(). The sub-query generates the following:
Notice the last column RN
. You may see that it is incremental YET partitioned by Location, Mgr, CId, CName, BDate, Age
and ordered by Item,PDate
Once the sub-query is resoved (with the RN), we then can apply the final aggretation which is essentially a pivot
The window function can be invaluable and well worth your time to get comfortable with them,
Upvotes: 1
Reputation: 945
I played around and this is what I came up with. John's is more efficient though.
WITH preSelect AS
(Select ROW_NUMBER() OVER(PARTITION BY Location,Mgr,CId,CName,BDate,Age
ORDER BY LOCATION) 'rowNum',
Location,Mgr,CId,CName,BDate,Age,Item,PDate
From @Test)
Select t.Location,t.Mgr,t.CId,t.CName,t.BDate,t.Age,
t1.Item 'Item 1',t1.PDate 'Date 1',
t2.Item 'Item 2',t2.PDate 'Date 2',
t3.Item 'Item 3',t3.PDate 'Date 3',
t4.Item 'Item 4',t4.PDate 'Date 4',
t5.Item 'Item 5',t5.PDate 'Date 5',
t6.Item 'Item 6',t6.PDate 'Date 6'
From @Test t
LEFT JOIN preSelect t1 ON t.Location = t1.Location AND t1.rowNum = 1
LEFT JOIN preSelect t2 ON t.Location = t2.Location AND t2.rowNum = 2
LEFT JOIN preSelect t3 ON t.Location = t3.Location AND t3.rowNum = 3
LEFT JOIN preSelect t4 ON t.Location = t4.Location AND t4.rowNum = 4
LEFT JOIN preSelect t5 ON t.Location = t5.Location AND t5.rowNum = 5
LEFT JOIN preSelect t6 ON t.Location = t6.Location AND t6.rowNum = 6
GROUP BY t.Location,t.Mgr,t.CId,t.CName,t.BDate,t.Age,
t1.Item,t1.PDate,t2.Item,t2.PDate,t3.Item,t3.PDate,t4.Item,t4.PDate,t5.Item,t5.PDate,t6.Item,t6.PDate
Upvotes: 0