TSQL透视多列

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TSQL透视多列相关的知识,希望对你有一定的参考价值。

码:

DECLARE @Employee TABLE
    (
        [Employee_Id] INT IDENTITY(1, 1)
      , [Code]        NVARCHAR(10)
    ) ;

INSERT INTO @Employee
VALUES ( N'E1' ), ( N'E2' ), ( N'E3' ) ;

DECLARE @Contact TABLE
    (
        [Employee_Id]  INT
      , [PhoneType]    CHAR(1)
      , [PhoneNumber]  VARCHAR(20)
      , [IsMainNumber] BIT
    ) ;

INSERT INTO @Contact
VALUES (1, 'M', '1234567890', 1), (1, 'H', '1234567891', 0),
       (1, 'M', '1234567892', 0), (1, 'B', '1234567893', 0),
       (2, 'M', '2234567890', 0), (2, 'H', '2234567891', 1),
       (2, 'B', '2234567892', 0), (2, 'M', '2234567893', 0),
       (3, 'M', '3234567890', 0), (3, 'H', '3234567891', 0),
       (3, 'M', '3234567892', 0), (3, 'B', '3234567893', 1);

SELECT  
    [E].[Employee_Id],
    [E].[Code],
    [COA].[MainPhoneNumber],
    [COA].[NonMainNumber]
FROM
    @Employee AS [E]
OUTER APPLY
    (SELECT      
         MAX (IIF([C].[IsMainNumber] = 1, [C].[PhoneNumber], NULL)) [MainPhoneNumber],
         MAX (IIF([C].[IsMainNumber] = 0, [C].[PhoneNumber], NULL)) [NonMainNumber]
     FROM        
         @Contact AS [C]
     WHERE       
         [E].[Employee_Id] = [C].[Employee_Id]
     GROUP BY    
         [C].[Employee_Id]) AS [COA] ;

电流输出

Employee_Id Code    MainPhoneNumber NonMainNumber
1           E1      1234567890      1234567893
2           E2      2234567891      2234567893
3           E3      3234567893      3234567892

目标

我需要返回MAX主电话号码及其电话类型和MAX非主电话号码及其电话类型。我能够获得MAX主要/非主要电话号码,但需要以某种方式获取他们的手机类型。我不想基于Employee_Id和PhoneNumber进行两次额外的连接并得到类型,因为原始表格很大并且会减慢很多东西。试图找出一个表现良好的替代方案。

期望的输出

Employee_Id Code    MainPhoneType   MainPhoneNumber NonMainPhoneType    NonMainNumber
1           E1      M               1234567890      B                   1234567893
2           E2      H               2234567891      M                   2234567893
3           E3      B               3234567893      M                   3234567892
答案

似乎你需要两个apply

select e.Employee_Id, e.Code, 
       c.PhoneType as MainPhoneType, c.PhoneNumber as MainPhoneNumber, 
       c1.PhoneType as NonMainPhoneType, c1.PhoneNumber as NonMainNumber
from @Employee e outer apply
     (select top (1) c.PhoneType, c.PhoneNumber
      from @Contact c
      where c.Employee_Id = e.Employee_Id and
            c.IsMainNumber = 1
      order by c.phonetype 
     ) c outer apply 
     (select top (1) c1.PhoneType, c1.PhoneNumber
      from @Contact c1
      where c1.Employee_Id = e.Employee_Id and
            c1.IsMainNumber = 0
      order by c1.phonetype 
     ) c1;

如果你不想做JOIN两次然后你可以使用临时表只是转储与相关index的联系人

#Tempie(Employee_Indi,Kisminumber)Inchlude(Phonetype,Phonenumber)

insert into #temp (Employee_Id, PhoneType, PhoneNumber, IsMainNumber)
    select Employee_Id, PhoneType, PhoneNumber, IsMainNumber
    from (select *, row_number() over (partition by Employee_Id, IsMainNumber order by PhoneType) as seq
          from @Contact
         ) c
     where seq = 1    

现在,您不需要再次使用@Contact

select e.*, m.*
from @Employee e cross apply
     (select max(case when t.IsMainNumber = 1 then t.PhoneType end) as MainPhoneType, 
             max(case when t.IsMainNumber = 1 then t.PhoneNumber end) as MainPhoneNumber,
             max(case when t.IsMainNumber = 0 then t.PhoneType end) as NonMainPhoneType, 
             max(case when t.IsMainNumber = 0 then t.PhoneNumber end) as NonMainNumber
      from #temp t
      where t.Employee_Id = e.Employee_Id               
     ) m;
另一答案

不确定如何确定哪个nonMainNumber是你想要的。似乎大多数样本数据都有几行可以返回。我会把这个练习留给你。以下是如何使用某些条件聚合的方法。

select x.Employee_Id
    , x.Code
    , MainPhoneType = max(case when x.RowNum = 1 then x.PhoneType end)
    , MainPhoneNumber = max(case when x.RowNum = 1 then x.PhoneNumber end)
    , NonMainPhoneType = max(case when x.RowNum = 2 then x.PhoneType end)
    , NonMainPhoneNumber = max(case when x.RowNum = 2 then x.PhoneNumber end)
from
(
    select e.Employee_Id
        , e.Code
        , c.PhoneType
        , c.PhoneNumber
        , RowNum = ROW_NUMBER() over(partition by e.Employee_Id order by c.IsMainNumber desc, c.PhoneType) --Not sure how you determine the non MainNumber when there are several to pick from
    from @Employee e
    join @Contact c on c.Employee_Id = e.Employee_Id
) x
group by x.Employee_Id
    , x.Code
另一答案

您可以使用条件聚合执行此操作:

select e.Employee_Id, e.Code
       max(case when seqnum = 1 and c.PhoneType = 'M' then c.PhoneType end) as MainPhoneType
       max(case when seqnum = 1  and c.PhoneType = 'M' then x.PhoneNumber end) as MainPhoneNumber,
       max(case when seqnum = 1 and c.PhoneType <> 'M' then c.PhoneType end) as NonMainPhoneType
       max(case when seqnum = 1  and c.PhoneType <> 'M' then c.PhoneNumber end) as NonMainPhoneNumber
from @Employee e join
     (select c.*,
             row_number() over (partition by c.Employee_Id
                                             (case when PhoneType = 'M' then  'M' end)
                                order by c.PhoneNumber desc
                               ) as seqnum
      from @Contact c
     ) c
     on c.Employee_Id = e.Employee_Id
group by e.Employee_Id, e.Code;

这个逻辑中的关键思想是partition by条款。它将两种类型的手机分为两组 - 其中'M'为“main”,NULL为其他所有。

以上是关于TSQL透视多列的主要内容,如果未能解决你的问题,请参考以下文章

TSQL 透视或估计模型复制

反透视具有多列的数据 - 请语法帮助

透视多列sql server

SQL Server:多列的动态数据透视

Excel中数据透视选择了多列数据后,会出现一个表头,这个是啥原因,怎么删除啊。

将行值反透视到多列