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

そして、1時間あたりの労働者の出力を望みます(最も近い時間に丸めます)理論上の出力は次のようになります。

 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 時にも作業を続けています。そのうちの 1 つは午前 10 時に出発します。等

4

7 に答える 7

0

まず、時間を最も近い時間に切り上げる必要があります

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

最初に見たように、元の時間に 30 分を追加します。(DATEADD(MI, 30, TimeStamp))
この方法では切り上げまたは切り上げ08:04も行われます。一部の労働者は少し早く働き始めることができると思いますので、早めに入札してください08: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 JOINGROUP 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 フィドルを確認してください

于 2015-07-18T06:03:12.740 に答える
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

難しいのは、データが欠落しているゼロを作成することです。通常のアプローチは、考えられるすべての「スロット」のリストを生成してから、実際のデータに外部結合を行うことです。これを一度に 1 日だけ実行したいと考えています。

単なる例である私のアプローチは、それぞれ 6 行と 4 行の 2 つのテーブルのクロス結合を行い、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

ここに私の最終的な作業コードがあります:

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

まず、datepart を使用して次のようにその日の時間を取得し、次に group by user を使用できます

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

これを行うには、多くの個別のパーツを接着する必要があります。最初の四捨五入は、日付の時間部分 + 30 分を取得することで簡単に実行できます。次に、開始レコードと終了レコードを決定します。これを示すフィールドがなく、1 日の最初の発生がログインまたは開始であると想定する場合は、row_number を使用し、奇数を開始レコードとして使用できます。

lead次に、開始と終了を結合する必要があります.SQL Server 2012以降では、これは関数で簡単に実行できます

不足している時間を取得するには、すべての時間でシーケンスを作成する必要があります。これにはいくつかのオプションがあります (良いリンクはこちら) が、リンクで使用されている sys.all_objects など、十分な行が確実に含まれている (順序付けのための適切な列がある) テーブルで row_number を使用するアプローチが気に入っています。そうすれば、7 時から 19 時までを次のように作成できます。select top 13 ROW_NUMBER() over (order by object_id) + 6 [Hour] from sys.all_objects

チェックする日付が 1 つしかない場合、クエリは単純にタイムスタンプ フィンガープリントの時間に左結合できます。それ以上の日付がある場合は、すべての日付を取得するために、時間にクロス適用された 2 番目のシーケンスを作成できます。1 つの日付を想定すると、最終的なコードは次のようになります。

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 に答える