0

我有一个带有指纹时间戳的日志,如下所示:

Usr   TimeStamp
-------------------------
 1    2015-07-01 08:01:00
 2    2015-07-01 08:05:00
 3    2015-07-01 08:07:00
 1    2015-07-01 10:05:00
 3    2015-07-01 11:00:00
 1    2015-07-01 12:01:00
 2    2015-07-01 13:03:00
 2    2015-07-01 14:02:00
 1    2015-07-01 16:03:00
 2    2015-07-01 18:04:00

我希望每小时有一个工人的输出(四舍五入到最接近的小时)理论输出应该是:

 7:00  0
 8:00  3
 9:00  3
 10:00 2
 11:00 1
 12:00 2
 13:00 1
 14:00 2
 15:00 2
 16:00 1
 17:00 1
 18:00 0
 19:00 0

任何人都可以考虑如何将其作为 SQL 来处理,或者如果没有其他方式,可以通过 TSQL 来处理?

编辑:时间戳是不同用户的登录和注销。所以在上午 8 点有 3 个用户登录,同样的 3 个用户在上午 9 点仍在工作。其中一人在上午 10 点离开。ETC

4

7 回答 7

0

您需要一张datetime hour桌子来执行此操作。

注意:这只是显示查询应如何工作一天的示例。CTE用表替换datetime hour。在datetime hour表格中,每个日期都应以小时开始并以小时07:00:00结束19:00:00

如果您想执行此操作超过一天,则可能必须包含其中Cast(dt.date_time AS DATE)select区分group by小时属于哪一天

WITH datetime_table 
     AS (SELECT '2015-07-01 07:00:00' AS date_time 
         UNION ALL 
         SELECT '2015-07-01 08:00:00' 
         UNION ALL 
         SELECT '2015-07-01 09:00:00' 
         UNION ALL 
         SELECT '2015-07-01 10:00:00' 
         UNION ALL 
         SELECT '2015-07-01 11:00:00' 
         UNION ALL 
         SELECT '2015-07-01 12:00:00' 
         UNION ALL 
         SELECT '2015-07-01 13:00:00' 
         UNION ALL 
         SELECT '2015-07-01 14:00:00' 
         UNION ALL 
         SELECT '2015-07-01 15:00:00' 
         UNION ALL 
         SELECT '2015-07-01 16:00:00' 
         UNION ALL 
         SELECT '2015-07-01 17:00:00' 
         UNION ALL 
         SELECT '2015-07-01 18:00:00' 
         UNION ALL 
         SELECT '2015-07-01 19:00:00') 
SELECT Datepart(hour, dt.date_time), 
       Hour_count=Count(t.id) 
FROM   datetime_table dt 
       LEFT OUTER JOIN Yourtable t 
                    ON Cast(t.dates AS DATE) = Cast(dt.date_time AS DATE) 
                       AND Datepart(hour, t.dates) = 
                           Datepart(hour, dt.date_time) 
GROUP  BY Datepart(hour, dt.date_time) 
于 2015-07-18T04:53:06.390 回答
0

您只需要按小时和日期分组。检查以下查询,希望对您有所帮助:

Create table #t1
(
usr int,
timelog datetime
)

 Insert into #t1 values(1, '2015-07-01 08:01:00')
 Insert into #t1 values(2,    '2015-07-01 08:05:00')
 Insert into #t1 values(3,    '2015-07-01 08:07:00')
 Insert into #t1 values(1,    '2015-07-01 10:05:00')
 Insert into #t1 values(3,    '2015-07-01 11:00:00')
 Insert into #t1 values(1,    '2015-07-01 12:01:00')
 Insert into #t1 values(2,    '2015-07-01 13:03:00')
 Insert into #t1 values(2,    '2015-07-01 14:02:00')
 Insert into #t1 values(1,    '2015-07-01 16:03:00')
 Insert into #t1 values(2,    '2015-07-01 18:04:00')

Select cast(timelog as varchar(11)) as LogDate, Datepart(hour, timelog) as LogTime, count(usr) as UserCount from #t1
Group by Datepart(hour, timelog), cast(timelog as varchar(11))
于 2015-07-18T05:00:16.803 回答
0

首先,您可以使用 datepart 获取以下日期的小时数,然后按用户使用 group

SELECT DATEPART(HOUR, GETDATE());

SQL小提琴

SELECT Convert(varchar(5),DATEPART(HOUR, timestamp)) + ':00' as time,
count(usr) as users
from tbl
group by DATEPART(HOUR, timestamp)
于 2015-07-18T04:47:23.233 回答
0

更难的部分是创建数据丢失的零点。通常的方法是生成所有可能“槽”的列表,然后对实际数据进行外部连接。我假设您一次只想运行一天。

我的方法只是一个例子,因为它对两个分别有 6 行和 4 行的表进行交叉连接,并且 6 乘以 4 是 24。

select f1.d * 6 + f0.d, coalesce(data.cnt, 0)
from
    (
        select 0 as d union all select 1 union all select 2 union all 
        select 3 union all select 4 union all select 5
    ) as f0,

    (
        select 0 as d union all select 1 union all
        select 2 union all select 3
    ) as f1
    left outer join
    (
        select
            cast(datepart(hh, TimeStamp) as varchar(2)) + ':00' as hr,
            count(*) as cnt
        from LOG
        group by datepart(hh, TimeStamp)
    ) as data
        on data.hr = f1.d * 6 + f0.d
于 2015-07-18T05:01:14.217 回答
0

首先,您需要将时间四舍五入到最接近的时间

DATEADD(HOUR, DATEDIFF(HOUR, 0, DATEADD(MI, 30, TimeStamp)), 0)

正如您首先看到的,我们在原始时间上增加了 30 分钟。(DATEADD(MI, 30, TimeStamp))
这种方法将四舍五入08:0408:0007:588:00。我认为一些工人可以提前开始工作

SELECT DATEADD(HOUR, DATEDIFF(HOUR, 0, DATEADD(MI, 30, TimeStamp)), 0) As FingertipTime
FROM Fingertips

如果您经常使用四舍五入的时间戳,您可以创建一个计算列

ALTER TABLE Fingertips ADD RoundedTimeStamp AS (DATEADD(HOUR, DATEDIFF(HOUR, 0, DATEADD(MI, 30, TimeStamp)), 0));

为了将时间戳与工作时间常数进行比较,您可以找到不同的方法。我将使用一个类型的变量来TABLE生成当天的工作时间
然后使用我们得到时间戳的LEFT JOIN数量GROUP BY

DECLARE @WorkHours TABLE(WorkHour DATETIME)
INSERT INTO @WorkHours (WorkHour) VALUES
('2015-07-01 07:00'),
('2015-07-01 08:00'),
('2015-07-01 09:00'),
('2015-07-01 10:00'),
('2015-07-01 11:00'),
('2015-07-01 12:00'),
('2015-07-01 13:00'),
('2015-07-01 14:00'),
('2015-07-01 15:00'),
('2015-07-01 16:00'),
('2015-07-01 17:00'),
('2015-07-01 18:00'),
('2015-07-01 19:00')

SELECT wh.Workhour
, COUNT(ft.TimeStamp) As Quantity
FROM @WorkHours wh
LEFT JOIN Fingertips ft ON ft.RoundedTimeStamp = wh.WorkHour
GROUP BY wh.WorkHour

检查这个SQL Fiddle

于 2015-07-18T06:03:12.740 回答
0

这是我的最终工作代码:

create table tsts(id int, dates datetime)
insert tsts values
(1 ,   '2015-07-01 08:01:00'),
(2 ,   '2015-07-01 08:05:00'),
(3 ,   '2015-07-01 08:07:00'),
(1 ,   '2015-07-01 10:05:00'),
(3 ,   '2015-07-01 11:00:00'),
(1 ,   '2015-07-01 12:01:00'),
(2 ,   '2015-07-01 13:03:00'),
(2 ,   '2015-07-01 14:02:00'),
(1 ,   '2015-07-01 16:03:00'),
(2 ,   '2015-07-01 18:04:00')

select horas.hora, isnull(sum(math) over(order by horas.hora rows unbounded preceding),0) as Employees from

(
select 0 as hora union all
select 1 as hora union all
select 2 as hora union all
select 3 as hora union all
select 4 as hora union all
select 5 as hora union all
select 6 as hora union all
select 7 as hora union all
select 8 as hora union all
select 9 as hora union all
select 10 as hora union all
select 11 as hora union all
select 12 as hora union all
select 13 as hora union all
select 14 as hora union all
select 15 as hora union all
select 16 as hora union all
select 17 as hora union all
select 18 as hora union all
select 19 as hora union all
select 20 as hora union all
select 21 as hora union all
select 22 as hora union all
select 23
) as horas

left outer join 
(
select hora, sum(math) as math from 
    (
    select id, hora, iif(rowid%2 = 1,1,-1) math from 
        (
        select row_number() over (partition by id order by id, dates) as rowid, id, datepart(hh,dateadd(mi, 30, dates)) as hora from tsts 
        ) as Q1
    ) as Q2
group by hora
) as Q3 

on horas.hora = Q3.hora

SQL小提琴

于 2015-07-18T06:27:24.677 回答
0

许多单独的部分必须粘合在一起才能完成。第一次四舍五入,这很容易通过获取日期的小时部分 + 30 分钟来完成。然后确定开始和结束记录。如果没有字段表明这一点并且假设一天的第一次出现是登录或开始,您可以使用 row_number 并使用奇数作为开始记录。

然后 start 和 end 必须耦合,在 sql server 2012 及更高版本中,这可以通过lead函数轻松完成

要获得缺失的小时数,必须创建包含所有小时数的序列。有几个选项(这里有很好的链接),但我喜欢在肯定包含足够行的表上使用 row_number 的方法(具有适当的列用于排序),例如链接中使用的 sys.all_objects。这样,可以将 7 到 19 小时创建为:select top 13 ROW_NUMBER() over (order by object_id) + 6 [Hour] from sys.all_objects

如果只有一个日期要检查,则查询可以简单地在时间戳指纹的时间点进行左连接。如果有更多日期,则可以创建第二个序列,将其交叉应用于时间以获取所有日期。假设一个日期,最终代码将是:

declare @t table(Usr int, [timestamp] datetime)

insert @t values
(1  ,   '2015-07-01 08:01:00'),
(2 ,   '2015-07-01 08:05:00'),
(3 ,   '2015-07-01 08:07:00'),
(1 ,   '2015-07-01 10:05:00'),
(3 ,   '2015-07-01 11:00:00'),
(1 ,   '2015-07-01 12:01:00'),
(2 ,   '2015-07-01 13:03:00'),
(2 ,   '2015-07-01 14:02:00'),
(1 ,  '2015-07-01 16:03:00'),
(2 ,   '2015-07-01 18:04:00'),
(2 ,   '2015-07-01 18:04:00')

;with usrHours as
(
    select Usr, datepart(hour, DATEADD(minute,30, times.timestamp)) [Hour] --convert all times to the rounded hour (rounding by adding 30 minutes)
     , ROW_NUMBER() over (partition by usr order by [timestamp] ) rnr
    from @t times --@t should be your logging table
), startend as --get next (end) hour by using lead
(
    select Usr, [hour] StartHour , LEAD([Hour]) over (partition by usr order by rnr) NextHour  ,rnr
    from usrHours
),hours as --sequence of hours 7 to 19
(
    select top 13 ROW_NUMBER() over (order by object_id) + 6 [Hour] from sys.all_objects
)

select cast([Hour] as varchar) + ':00' [Hour], COUNT(startend.usr) Users 
from hours --sequence is leading
left join startend on hours.Hour between startend.StartHour and startend.NextHour 
                                and rnr % 2  = 1 --every odd row number is a start time
group by Hours.hour
于 2015-07-18T06:31:53.890 回答