我有一个带有指纹时间戳的日志,如下所示:
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
任何人都可以考虑如何通过TSQL来解决这个问题吗?或者没有其他办法?
编辑:时间戳是不同用户的登录和注销。因此,早上8点,有3位用户登录,同样3位用户仍在上午9点工作。其中一人在上午10点离开。等
答案 0 :(得分:0)
首先,您可以使用datepart获取以下日期的小时数,然后按用户分组
SELECT DATEPART(HOUR, GETDATE());
SELECT Convert(varchar(5),DATEPART(HOUR, timestamp)) + ':00' as time,
count(usr) as users
from tbl
group by DATEPART(HOUR, timestamp)
答案 1 :(得分: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)
答案 2 :(得分:0)
您只需要按小时和日期分组。请查看以下查询,希望这可以帮助您:
ng-click
答案 3 :(得分:0)
更难的部分是创建缺少数据的零。通常的方法是生成所有可能的#34;插槽的列表。然后对实际数据进行外连接。我假设您只想一次运行一天。
我的方法只是一个例子,因为它分别有两个表的交叉连接,分别有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
答案 4 :(得分:0)
首先,你需要将时间四舍五入到最接近的时间
DATEADD(HOUR, DATEDIFF(HOUR, 0, DATEADD(MI, 30, TimeStamp)), 0)
如您所见,我们将原始时间(DATEADD(MI, 30, TimeStamp))
添加30分钟
此方法也会将08:04
向08:00
或07:58
向8:00
向上舍入。
我假设有些工人可以提早开始工作
SELECT DATEADD(HOUR, DATEDIFF(HOUR, 0, DATEADD(MI, 30, TimeStamp)), 0) As FingertipTime
FROM Fingertips
如果您经常使用舍入时间戳
,则可以创建Computed columnALTER 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
答案 5 :(得分: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
答案 6 :(得分:0)
许多单独的部件必须粘在一起才能完成。 首先进行舍入,可以轻松完成日期+ 30分钟的小时部分。然后确定开始和结束记录。如果没有字段来指示这一点并假设第一次出现的是登录或开始,则可以使用row_number并使用奇数作为开始记录。
然后开始和结束必须耦合,在sql server 2012及更高版本中,这可以通过lead
函数轻松完成
要获取缺失的小时,必须创建一个包含所有小时的序列。有几个选项(良好的链接here),但我喜欢在一个表上使用row_number的方法,该表肯定包含足够的行(有一个适当的列用于order by),例如在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