-2

すべてのスタッフのシフト時間を計算する必要があります。

OLTP システムからデータを取得し、日付、スタッフ、およびログイン ログアウト時間を返すクエリを作成しました。ログイン時間とログアウト時間は、システム内の 2 つの別個のトランザクションですが、ログイン時間とログアウト時間を 1 つの行にしたいです。入力として取得するものと出力として必要なものの下の画像を参照してください。私の目標を達成するためにクエリを書き留めてください。

行を列に

4

2 に答える 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 を見つけます (行がログインの場合、これはログアウトであると想定され、最も外側の行はログイン行を選択するだけです。

正直なところ、データ構造を考えると、サブクエリを使用した最初のバージョンの方が好きだと思います。

于 2013-07-04T19:28:50.457 に答える
0

データを非正規化する必要がある場合は、自己結合を使用するのが好きです。私は 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;

その他の注意事項:

  1. あなたは時間を計算しなければならないと言いました。これは、同じクエリで実行できます。この場合、「経過」列は分を計算します。(目的に合わせて の最初のパラメーターを変更DateDiffhourます。)

@ゴードン・リノフ

  1. ログインが 1 日で、ログアウトが別の日である場合、クエリは状況を正しく処理します。
于 2013-07-09T02:51:33.350 に答える