如何将数据分成两列
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
试试这个 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
考虑以下 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
试试这个 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