すべてのスタッフのシフト時間を計算する必要があります。
OLTP システムからデータを取得し、日付、スタッフ、およびログイン ログアウト時間を返すクエリを作成しました。ログイン時間とログアウト時間は、システム内の 2 つの別個のトランザクションですが、ログイン時間とログアウト時間を 1 つの行にしたいです。入力として取得するものと出力として必要なものの下の画像を参照してください。私の目標を達成するためにクエリを書き留めてください。
すべてのスタッフのシフト時間を計算する必要があります。
OLTP システムからデータを取得し、日付、スタッフ、およびログイン ログアウト時間を返すクエリを作成しました。ログイン時間とログアウト時間は、システム内の 2 つの別個のトランザクションですが、ログイン時間とログアウト時間を 1 つの行にしたいです。入力として取得するものと出力として必要なものの下の画像を参照してください。私の目標を達成するためにクエリを書き留めてください。
本当に必要なのはlag()
関数ですが、SQL Server 2008 では使用できません。したがって、サブクエリでエミュレートできます。
select i.day, i.staff, i.login,
(select top 1 logout
from input i2
where i2.staff = i.staff and
i2.day = i.day and
i2.login = cast(login as date) and
i2.logout >= i.login
order by i2.logout
) as LogOut
from input i
where logout = cast(logout as date)
このロジックは、時間コンポーネントがゼロlogout = cast(logout as date)
の行を識別することを目的としています。logout
これは、どのシフトも真夜中を超えないことを前提としています。
編集:
SQL Server 2012 では、同じクエリを使用できます。それを に置き換えるのlead()
は少し手間がかかります:
select day, staff, login, logout
from (select i.day, i.staff, thedate as login, which,
lead(thedate) over (partition by staff, day order by date) as LogOut
from (select i.day, i.staff,
(case when login = cast(login as date) then logout
else login
end) as thedate,
(case when login = cast(login as date) then 'logout'
else 'login'
end) as which
from input i
) i
) i
where which = 'login'
さらにサブクエリが必要です。問題は、2 つのフィールドの日付を比較しているため、最も内側のサブクエリがそれらを 1 つのフィールド ( 'thedate'
) に入れることです。次は nextdate を見つけます (行がログインの場合、これはログアウトであると想定され、最も外側の行はログイン行を選択するだけです。
正直なところ、データ構造を考えると、サブクエリを使用した最初のバージョンの方が好きだと思います。
データを非正規化する必要がある場合は、自己結合を使用するのが好きです。私は SQL Server 2012 で以下をテストしました。
データ:
DECLARE @t1 AS TABLE (
Day1 DATE
,Staff VARCHAR(3)
,Login DATETIME2
,Logout DATETIME2
);
INSERT INTO @t1
VALUES ('20130704', '123', '20130704 18:44:16.533', '20130704 00:00:00.000')
,('20130706', '456', '20130706 00:00:00.000', '20130706 01:10:12.000')
,('20130704', '123', '20130704 00:00:00.000', '20130704 20:24:16.553')
,('20130704', '123', '20130704 20:44:16.533', '20130704 00:00:00.000')
,('20130704', '123', '20130704 00:00:00.000', '20130704 22:54:16.553')
,('20130705', '456', '20130705 08:45:12.550', '20130705 00:00:00.000');
解決:
SELECT a.Day1, a.Staff, a.Login, MIN(b.Logout) AS Logout,
DateDiff(minute, a.login, MIN(b.logout)) AS Elapsed
FROM @t1 a join @t1 b
ON a.Staff = b.Staff AND a.Login < b.Logout AND CONVERT(TIME, a.Login) > '00:00:00.00'
GROUP BY a.Day1, a.Staff, a.Login;
その他の注意事項:
DateDiff
しhour
ます。)@ゴードン・リノフ