如何将数据分成两列

How To Separate Data Into Two Columns

考虑以下 table 结构和示例数据 -

EmpID InputDateTime      StatusINOUT
-------------------------------------
1     2018-05-26 08:44     1
1     2018-05-26 08:44     2
2     2018-05-28 08:44     1
2     2018-05-28 12:44     2                   
1     2018-05-21 08:44     1
1     2018-05-21 10:44     2
2     2018-05-23 08:44     1
2     2018-05-23 08:44     2   

现在我想将 InputDateTime 列分成两列,即 INTIME(1)OUTTIME(2)。这背后的逻辑是 StatusInOut 为 1 的日期将为 InTime,对于 StatusInOut 为 2 的日期值将为 OUTTIME(2).

预期的输出格式如下所示:

Empid   INTIME(1)          OUTIME(2)
--------------------------------------------
1      2018-05-26 08:44    2018-05-26 08:44
2      2018-05-28 08:44    2018-05-28 12:44
1      2018-05-21 08:44    2018-05-21 10:44
2      2018-05-23 08:44    2018-05-23 08:44

这是我目前尝试过的方法

create table #tempStatus (EmpId int, intTime datetime, sStatus int)    
insert into #tempStatus    
values(1, '2018-05-26 08:44', 1),    
    (1, '2018-05-26 08:44', 2),    
    (2, '2018-05-28 08:44', 1),    
    (2, '2018-05-28 12:44', 2),        
    (1, '2018-05-21 08:44', 1),    
    (1, '2018-05-21 10:44', 2),        
    (2, '2018-05-23 08:44', 1),    
    (2, '2018-05-23 08:44', 2)    

select EmpId, MIN(intTime) as intTime, MIN(intTime) as OutTime into #tempA from (  
select EmpId, intTime, intTime as OutTime  
from #tempStatus where sStatus = 1  
)a   
group by EmpId, intTime  

select EmpId, MAX(outTime) as outTime into #tempB from(   
select EmpId, intTime as outTime  
from #tempStatus where sStatus = 2  
)b   
group by empId,outTime     

select * from #tempA order by EmpId  

drop table #tempA  
drop table #tempB  
DROP TABLE #tempStatus

您需要 row_number()s 并使用它们的差异来进行条件聚合,这也称为 Gaps and Islands 问题:

select empid, 
       max(case when sStatus = 1 then intTime end) as INTIME,
       max(case when sStatus = 2 then intTime end) as OUTIME
from (select t.*, 
             row_number () over ( order by inttime) as seq1,
             row_number () over (partition by empid order by inttime) as seq2
      from #tempStatus t
     ) t
group by empid, (seq1-seq2);

编辑: 如果您想在 InTime 不存在时显示 OutTime,那么您可以使用子查询:

select t.empid, 
       coalesce(INTIME, OUTIME) as INTIME,
       coalesce(OUTIME, INTIME) as OUTIME
from ( <query here> 
     ) t;

这是一个匹配结束时间和开始时间的问题:

WITH cte AS (
    SELECT EmpId, intTime, sStatus
         , ROW_NUMBER() OVER (PARTITION BY EmpId ORDER BY intTime) AS rn
    FROM #tempStatus
)
SELECT o.EmpId, i.intTime AS INTIME, o.intTime AS OUTIME
FROM cte o
LEFT JOIN cte AS i ON i.EmpId = o.EmpId AND i.rn = o.rn - 1 AND i.sStatus = 1
WHERE o.sStatus = 2

Demo on DB<>Fiddle and some tests

试试这个 PIVOT 样本数据

IF OBJECT_ID('Tempdb..#tempStatus')IS NOT NULL
DROP TABLE #tempStatus

CREATE TABLE #TEMPSTATUS (EMPID INT, INTTIME DATETIME, SSTATUS INT)    
INSERT INTO #TEMPSTATUS    
VALUES(1, '2018-05-26 08:44', 1),    
    (1, '2018-05-26 08:44', 2),    
    (2, '2018-05-28 08:44', 1),    
    (2, '2018-05-28 12:44', 2),        
    (1, '2018-05-21 08:44', 1),    
    (1, '2018-05-21 10:44', 2),        
    (2, '2018-05-23 08:44', 1),    
    (2, '2018-05-23 08:44', 2)    

Sql 脚本

SELECT Empid,[INTIME(1)],[OUTIME(2)]
FROM
(
    SELECT EmpId,intTime, CASE WHEN sStatus=1 THEN 'INTIME(1)' 
                       WHEN sStatus=2 THEN 'OUTIME(2)'  END INOutTimes
    FROM #tempStatus
    ) AS SRC
    PIVOT 
    (MAX(intTime) FOR INOutTimes IN ([INTIME(1)],[OUTIME(2)])
    ) AS PVT
UNION ALL
SELECT Empid,[INTIME(1)],[OUTIME(2)]
FROM
(
    SELECT EmpId,intTime, CASE WHEN sStatus=1 THEN 'INTIME(1)' 
                       WHEN sStatus=2 THEN 'OUTIME(2)'  END INOutTimes
    FROM #tempStatus
    ) AS SRC
    PIVOT 
    (MIN(intTime) FOR INOutTimes IN ([INTIME(1)],[OUTIME(2)])
    ) AS PVT

结果

Empid    INTIME(1)                   OUTIME(2)
---------------------------------------------------------------
1       2018-05-26 08:44:00.000     2018-05-26 08:44:00.000
2       2018-05-28 08:44:00.000     2018-05-28 12:44:00.000
1       2018-05-21 08:44:00.000     2018-05-21 10:44:00.000
2       2018-05-23 08:44:00.000     2018-05-23 08:44:00.000

我已经尝试在使用内部连接更新后找出解决方案,如下所示。这里我跳过了没有 InTime 的日期和行。

create table #tempStatus (EmpId int, intTime datetime, sStatus int)        
insert into #tempStatus        
values(1, '2018-05-26 08:44', 1),        
    (1, '2018-05-26 08:44', 2),        
    (2, '2018-05-28 08:44', 1),        
    (2, '2018-05-28 12:44', 2),            
    (1, '2018-05-21 08:44', 1),        
    (1, '2018-05-21 10:44', 2),            
    (2, '2018-05-23 08:44', 1),        
    (2, '2018-05-23 08:44', 2)  
    ,(3, '2018-05-23 08:44', 1)  

select EmpId, MIN(intTime) as intTime, MAX(intTime) as OutTime into #tempA from (      
select EmpId, intTime, intTime as OutTime      
from #tempStatus where sStatus = 1      
)a       
group by EmpId, intTime      

update s      
set s.OutTime = t.outTime      
from #tempA s      
left join     
(    
select EmpId, MAX(outTime) as outTime from(       
select EmpId, intTime as outTime      
from #tempStatus where sStatus = 2      
)b       
group by empId,outTime) t     
on s.EmpId = t.EmpId and Convert(Varchar,s.OutTime,112) =  Convert(Varchar,t.outTime,112)      

select * from #tempA order by EmpId      

drop table #tempA      
DROP TABLE #tempStatus

这是演示- Spltting Column