TSQL透视多列

问题描述 投票:2回答:3

码:

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
sql sql-server tsql sql-server-2014
3个回答
1
投票

似乎你需要两个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;

1
投票

不确定如何确定哪个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

1
投票

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

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为其他所有。

© www.soinside.com 2019 - 2024. All rights reserved.