在T-SQL中透视两列

时间:2017-04-27 19:46:20

标签: sql sql-server tsql pivot

首先 - 我已经看了两天的例子,并试图应用它们但没有成功。我不理解Pivot如何工作的机制,我希望得到一些帮助。

我有一个每个客户有多行的数据集 - 每次购买一行。 我希望每个客户获得一行 - 最多购买6个,每个购买日期。

老实说,我甚至不知道这是否可能......因为购买日期[PDate]可能变化如此广泛。 ?

这是我的起始数据集的SQL:

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

我需要看到这个:

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 .... 

...基本上,每个CId有一行: 位置,经理,CId,CName,BDate,年龄,项目1,日期1,项目2,日期2,项目3,日期3 ......最多购买6件商品。

提前致谢!

2 个答案:

答案 0 :(得分:1)

由于您不需要动态并且最大值为6,因此可以进行简单的条件聚合。

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

返回enter image description here

  

根据要求 - 一些评论

这是一个简单的条件聚合,有点扭曲。扭曲是使用窗口函数Row_Number()的子查询。子查询生成以下内容:

enter image description here

请注意最后一栏RN。您可能会看到它是由Location, Mgr, CId, CName, BDate, Age分区并按Item,PDate

排序的增量YET

一旦子查询被重新获得(使用RN),我们就可以应用最终的聚合,这实际上是一个支点

窗口功能非常宝贵,值得您花些时间来熟悉它们,

答案 1 :(得分:0)

我玩了,这就是我想出来的。约翰的效率更高。

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