Sql server 如何在SQL Server中为一个工作日内的多个时间戳将时间分类为输入和输出

Sql server 如何在SQL Server中为一个工作日内的多个时间戳将时间分类为输入和输出,sql-server,time,sql-server-2008-r2,Sql Server,Time,Sql Server 2008 R2,我有一张表,上面记录了员工从指纹机上取下的出入时间 员工可以在一段时间内(例如3分钟)对同一个入口和/或出口有许多指纹,我们称之为a 如果员工想确保机器得到他们的指纹,他们会在两种情况下这样做。如果公司里有很多指纹识别机,一台在大门附近,另一台在办公室附近 员工每天可以多次离开和返回,因为他们可能被要求这样做,在一段时间内必须留在公司,以便计算为工作时间并确定下一个指纹将退出(例如20分钟),我们称之为B 问题是: 在确定插入数据库的记录的进入和退出时间的过程中,有两个方面: 如果指纹是入口,我

我有一张表,上面记录了员工从指纹机上取下的出入时间

员工可以在一段时间内(例如3分钟)对同一个入口和/或出口有许多指纹,我们称之为a

如果员工想确保机器得到他们的指纹,他们会在两种情况下这样做。如果公司里有很多指纹识别机,一台在大门附近,另一台在办公室附近

员工每天可以多次离开和返回,因为他们可能被要求这样做,在一段时间内必须留在公司,以便计算为工作时间并确定下一个指纹将退出(例如20分钟),我们称之为B

问题是:

在确定插入数据库的记录的进入和退出时间的过程中,有两个方面:

如果指纹是入口,我们应该在一个小时内选择最短时间 在B之后已经考虑下一个指纹作为退出,但是选择最大时间

这是一个月的所有日子

请注意,有时工作日从早上8:00开始,到第二天早上7:59结束,我们称之为C

范例

emp_id      edate       etime
100     01/01/2015      08:00:00
100     01/01/2015      08:00:30
100     01/01/2015      08:00:58
100     01/01/2015      08:02:01
100     01/01/2015      10:00:00
100     01/01/2015      10:01:15
100     01/01/2015      10:01:50
100     01/01/2015      12:10:00
100     01/01/2015      12:10:50
100     01/01/2015      12:11:00
100     01/01/2015      13:50:10
100     01/01/2015      13:52:30
100     01/01/2015      13:52:31
100     02/01/2015      01:00:31
100     02/01/2015      01:01:31
100     02/01/2015      01:52:31
100     02/01/2015      04:59:31
我想编写一个SQL Server查询,结果如下所示:

emp_id  edate           InTime          OutTime
100     01/01/2015      08:00:00        10:01:50        
100     01/01/2015      12:10:00        13:52:31
100     01/01/2015      01:00:31        01:52:31
100     01/01/2015      01:00:31        01:52:31
100     01/01/2015      04:59:31        null
第二天也一样


我可以使用任何UI语言的
datagrid
中的循环和条件来执行此操作,但这需要花费大量时间,尤其是在计算许多员工整整一个月或更长时间的循环和条件时。

如果您的SQL版本为2012或更高版本,请尝试以下查询:

    select emp_id,[date],max(intime) as InTime, max(outtime) as OutTime
    from
    (
    select 
        emp_id,
        cast(combdt as date) as [date],
        case 
        when row_number() over (partition by emp_id,cast(combdt as date) order by etime1 asc)%2 =1
        then etime1 else null 
        end as intime,
        case 
        when row_number() over (partition by emp_id,cast(combdt as date) order by etime1 asc)%2 =0
        then etime2 else null
        end as outtime,
        (row_number() over (partition by emp_id,cast(combdt as date) order by etime1 asc)+1)/2 as badge
    from 
    (
    --since min of entry is taken and max of exit is taken 
    -- I'm apply the comparision between min and max to determine the logic of B
    select * from
        (
        select 
            t.emp_id,
            t.combdt,
            min(t.combdt) as etime1,
            t.etime2, 
            case 
                when DATEDIFF(mi,ISNULL(lag(etime2) over(partition by t.emp_id,cast(combdt as date) order by etime2),0),min(t.combdt)) >20
                then 1 
                else 0
            end as flag 
        from
            (
                select 
                    t1.emp_id,
                    t1.combdt,
                    max(t2.combdt) as etime2,
                    max(t2.r) as r2 
                from
                    (
                        select 
                            *,
                            edate+etime as combdt,
                            row_number() over(partition by emp_id, edate order by etime asc) as r
                        from tbl 
                    )   t1
                left join 
                    (
                        select 
                            *,
                            edate+etime as combdt,
                            row_number() over(partition by emp_id, edate order by etime asc) as r
                        from 
                        tbl 
                    )   t2
                    on t1.emp_id=t2.emp_id and 
                        dateadd(mi,3,t1.combdt)>t2.combdt -- this is where we put A
                    group by t1.emp_id, t1.combdt,t1.r
            )t
        group by t.emp_id,t.combdt,t.etime2
        )t where flag =1
    )t
    )t
    group by emp_id,[date],badge
此长查询的输出为:

emp_id          date       InTime       OutTime
100 2015-01-01  2015-01-01 08:00:00.000 2015-01-01 10:01:50.000
100 2015-01-01  2015-01-01 12:10:00.000 2015-01-01 13:52:31.000
100 2015-02-01  2015-02-01 01:00:31.000 2015-02-01 01:52:31.000
100 2015-02-01  2015-02-01 04:59:31.000 NULL
演示的SQl fiddle链接如下:

p.S.:请注意,上述问题太长,因为它包含多个小问题,如A和B、日期重叠约束和从连续条目计算输入输出,并且不提供SQL版本

如果您使用的是SQLServer版本,它不支持<代码> Real/Lead 函数,请考虑使用<代码>连接< /代码>。
有很多这样的例子可以告诉你如何做。

首先,我找到了一种查询员工出入的方法,将时间表与时间表连接起来,然后选择最适合的行作为一个最佳入口“min()”和第二个出口最大(),但后来我意识到,如果我能用另一种更好的方式,我会把它作为一个答案,我希望任何人可能需要可以采取或使用的想法

我注意到,如果时间在同一小时内,但分钟差小于(3分钟),那么我的时间的每一组行都有一些共同点

我需要以第1行开始的奇数行的(max())作为我的第一个输入

偶数行的(min())是前一个奇数行的出口

我选择了times列,并添加了另一个计算列,以确定哪一个时间比另一个时间(20分钟)多分钟,这是员工可以在办公室停留的最短时间

datepart(hour,histIn.etime) + 
(
  case when datepart(MINUTE,histIn.etime)>=20 
  then 1 else 0 end
) hr
借助
densite\u RANK()
按新计算列的顺序对行进行编号。 然后我需要选择每一个奇数行作为开始时间,每一个偶数行将成为我的结束时间

,case when RowIdx%2<>0 then min(InTime) end InTime
 ,case when (RowIdx+1)%2<>0 then max(InTime) end OutTime
这是@DhruvJoshi的手

最后选择一对夫妇,让他们结婚

select emp_id,edate,max(InTime)InTime,max(OutTime)OutTime,badge Counts
以下是插页:

create table tbl (emp_id int, edate datetime, etime time(0));

insert into tbl values
(100,'01/01/2015','08:00:00'),
(100,'01/01/2015','08:00:30'),
(100,'01/01/2015','08:00:58'),
(100,'01/01/2015','08:02:01'),
(100,'01/01/2015','10:00:00'),
(100,'01/01/2015','10:01:15'),
(100,'01/01/2015','10:01:50'),
(100,'01/01/2015','10:10:50'),
(100,'01/01/2015','12:10:00'),
(100,'01/01/2015','12:10:50'),
(100,'01/01/2015','12:11:00'),
(100,'01/01/2015','13:50:10'),
(100,'01/01/2015','13:52:30'),
(100,'01/01/2015','13:52:31'),
(100,'01/01/2015','15:52:31'),
(100,'02/01/2015','01:00:31'),
(100,'02/01/2015','01:01:31'),
(100,'02/01/2015','01:52:31'),
(100,'02/01/2015','04:59:31'),
(100,'02/01/2015','08:59:31'),
(100,'02/01/2015','10:59:31'),
(200,'01/01/2015','08:10:00'),
(200,'01/01/2015','08:10:30'),
(200,'01/01/2015','08:10:58'),
(200,'01/01/2015','08:12:01'),
(200,'01/01/2015','10:05:00'),
(200,'01/01/2015','10:05:15'),
(200,'01/01/2015','10:05:50'),
(200,'01/01/2015','10:15:50'),
(200,'01/01/2015','12:15:00'),
(200,'01/01/2015','12:10:50'),
(200,'01/01/2015','12:11:00'),
(200,'01/01/2015','14:50:10'),
(200,'01/01/2015','14:52:30'),
(200,'01/01/2015','14:52:31'),
(200,'02/01/2015','04:00:31'),
(200,'02/01/2015','01:01:31'),
(200,'02/01/2015','01:52:31'),
(200,'02/01/2015','04:59:31'),
(200,'02/01/2015','08:59:31'),
(200,'02/01/2015','10:59:31')
以下是选择:

select emp_id,edate,max(InTime)InTime,max(OutTime)OutTime,badge Counts
from (
       select emp_id,edate
       ,case when RowIdx%2<>0 then min(InTime) end InTime
       ,case when (RowIdx+1)%2<>0 then max(InTime) end OutTime
       ,RowIdx
       ,(row_number() over (partition by emp_id,edate order by RowIdx asc)+1)/2 as badge
       from
       (
          select emp_id,edate,etime InTime
          ,datepart(hour,histIn.etime)+(case when datepart(MINUTE,histIn.etime)>=20 then 1 else 0 end)hr
          ,DENSE_RANK() over(partition by HistIn.emp_id,HistIn.edate
          order by emp_id,edate
          ,datepart(hour,histIn.etime)+(case when datepart(MINUTE,histIn.etime)>=20 then 1 else 0 end)
          )RowIdx 
          from tbl HistIn 
       )aa
       group by emp_id,edate,RowIdx
    )bb
group by emp_id,edate,badge
order by emp_id,edate,badge
选择emp_id、edate、max(InTime)InTime、max(OutTime)OutTime、徽章计数
从(
选择emp_id,edate
,当RowIdx%20时,则为min(InTime)end InTime
,当(RowIdx+1)%20时,则最大(InTime)结束超时
,RowIdx
,(按emp_id划分的行数(),按RowIdx asc划分的数据顺序)+1)/2作为徽章
从…起
(
选择emp_id、edate、etime InTime
,datepart(hour,histIn.etime)+(datepart(MINUTE,histIn.etime)大于等于20时,则1或0结束)hr
,通过HistIn.emp\u id,HistIn.edate进行分区
由emp_id、edate订购
,datepart(hour,histIn.etime)+(datepart(MINUTE,histIn.etime)>=20时的大小写为1,否则为0结束)
)RowIdx
来自tbl组氨酸
)aa
按emp_id、edate、RowIdx分组
)bb
按emp_id、edate、徽章分组
按emp_id、edate、徽章订购
他们都在这里与此链接:


谢谢大家。

首先,不幸的是,我的sql server版本是2008-r2。第二,考虑在两天内填写一天,因此日期必须显示为“2015年8月1日”,即使时间是在第二天“2015年8月2日”,直到此处规定的截止时间为上午7:59,从2015年8月2日上午8:00开始,任何新的时间都将被视为接下来的几天。谢谢您的快速回答,先生。在您的帮助下,我努力工作,从一种方式移动到另一种方式,我通过以下查询实现了这一目标:,现在等待您的评论,到那时,我将分享我的问题的答案…@W.R既然你得到了正确的答案,这与我发布的答案不同,我建议你继续并将其作为这个问题的新答案发布并接受它。@W.R既然这个答案似乎有助于你找到你的答案,我建议你接受它好吗?要接受答案,请单击答案左侧的勾号,使其变为绿色。谢谢
select emp_id,edate,max(InTime)InTime,max(OutTime)OutTime,badge Counts
from (
       select emp_id,edate
       ,case when RowIdx%2<>0 then min(InTime) end InTime
       ,case when (RowIdx+1)%2<>0 then max(InTime) end OutTime
       ,RowIdx
       ,(row_number() over (partition by emp_id,edate order by RowIdx asc)+1)/2 as badge
       from
       (
          select emp_id,edate,etime InTime
          ,datepart(hour,histIn.etime)+(case when datepart(MINUTE,histIn.etime)>=20 then 1 else 0 end)hr
          ,DENSE_RANK() over(partition by HistIn.emp_id,HistIn.edate
          order by emp_id,edate
          ,datepart(hour,histIn.etime)+(case when datepart(MINUTE,histIn.etime)>=20 then 1 else 0 end)
          )RowIdx 
          from tbl HistIn 
       )aa
       group by emp_id,edate,RowIdx
    )bb
group by emp_id,edate,badge
order by emp_id,edate,badge