我有一个数据源,其员工按以下格式刷入/输出
+----------+---------+-----------+------------+-------+-----------+
| Forename | Surname | Clock_Num | Date | Time | Direction |
+----------+---------+-----------+------------+-------+-----------+
| John | Kerry | 0111 | 2017-09-21 | 18:00 | IN |
+----------+---------+-----------+------------+-------+-----------+
| John | Kerry | 0111 | 2017-09-22 | 02:00 | OUT |
+----------+---------+-----------+------------+-------+-----------+
| Bill | Long | 0112 | 2017-09-21 | 10:00 | IN |
+----------+---------+-----------+------------+-------+-----------+
| Bill | Long | 0112 | 2017-09-21 | 18:00 | OUT |
+----------+---------+-----------+------------+-------+-----------+
| George | Takai | 0113 | 2017-09-22 | 11:00 | IN |
+----------+---------+-----------+------------+-------+-----------+
现在我希望看到这些基于转换开始时间几乎转换为每位员工一条记录
+----------+---------+-----------+------------+------------------+------------------+
| Forename | Surname | Clock_Num | Shift Date | Time In | Time Out |
+----------+---------+-----------+------------+------------------+------------------+
| John | Kerry | 0111 | 2017-09-21 | 2017-09-21 18:00 | 2017-09-22 02:00 |
+----------+---------+-----------+------------+------------------+------------------+
| Bill | Long | 0112 | 2017-09-22 | 2017-09-22 10:00 | 2017-09-22 18:00 |
+----------+---------+-----------+------------+------------------+------------------+
| George | Takai | 0113 | 2017-09-22 | 2017-09-22 11:00 | Null |
+----------+---------+-----------+------------+------------------+------------------+
让我难倒的部分是查询的逻辑。
即如果没有时钟输出时间大于单日的时钟输入时间,则向前看下一个OUT,但只要它在下一个IN之前(如果员工忘记退出时),则显示为空
任何人都可以帮助或指出我正确的方向吗?
我接受可能没有一个简单的2-3行答案,因为大量的记录需要相对有效
答案 0 :(得分:2)
使用common table expression和lead()
窗口函数获取Next_Time
和cross apply()
以获取Time
之后的Time
'out' {1}}'in',但在'{
}中Next_Time
'之前
;with cte as (
select Forename, Surname, Clock_Num, Direction, Date
, Time = convert(datetime,t.Date)+convert(datetime,t.Time)
, Next_Time = lead(convert(datetime,t.Date)+convert(datetime,t.Time))
over (partition by Forename, Surname, Clock_Num, Direction
order by Date, Time)
from t
)
select t.Forename, t.Surname, t.Clock_Num, t.Date
, Time_In = t.Time
, Time_Out = x.Time
from cte as t
outer apply (
select top 1
o.Time
from cte as o
where o.Forename = t.Forename
and o.Surname = t.Surname
and o.Clock_Num = t.Clock_Num
and o.Direction = 'OUT'
and o.Time > t.Time
and (o.Time < t.Next_Time or t.Next_Time is null)
order by o.Time
) as x
where t.Direction = 'IN'
order by clock_num
rextester演示:http://rextester.com/UIMJ36919
返回:
+----------+---------+-----------+------------+---------------------+---------------------+
| Forename | Surname | Clock_Num | Date | Time_In | Time_Out |
+----------+---------+-----------+------------+---------------------+---------------------+
| John | Kerry | 111 | 2017-09-21 | 2017-09-21 18:00:00 | 2017-09-22 02:00:00 |
| Bill | Long | 112 | 2017-09-21 | 2017-09-21 10:00:00 | 2017-09-21 18:00:00 |
| George | Takai | 113 | 2017-09-22 | 2017-09-22 11:00:00 | NULL |
+----------+---------+-----------+------------+---------------------+---------------------+
对于2008年,您可以使用outer apply()
来模拟lead()
,如下所示:
;with cte as (
select Forename, Surname, Clock_Num, Direction, Date
, Time = convert(datetime,t.Date)+convert(datetime,t.Time)
, x.Next_Time
from t
outer apply (
select top 1
Next_Time = convert(datetime,o.Date)+convert(datetime,o.Time)
from t as o
where o.Forename = t.Forename
and o.Surname = t.Surname
and o.Clock_Num = t.Clock_Num
and o.Direction = t.Direction
and ((o.Date = t.Date and o.Time > t.Time)
or o.Date > t.Date)
order by o.Date, o.Time
) as x
)
select t.Forename, t.Surname, t.Clock_Num, t.Date
, Time_In = t.Time
, Time_Out = x.Time
from cte as t
outer apply (
select top 1
o.Time
from cte as o
where o.Forename = t.Forename
and o.Surname = t.Surname
and o.Clock_Num = t.Clock_Num
and o.Direction = 'OUT'
and o.Time > t.Time
and (o.Time < t.Next_Time or t.Next_Time is null)
order by o.Time
) as x
where t.Direction = 'IN'
order by clock_num
rextester演示:http://rextester.com/LEYS1651