質問

テーブル内の次の情報を変換できる単一のクエリを探しています

name:time    :state
a   :10:00 AM:login
b   :10:05 AM:login
a   :10:06 AM:chatting
a   :10:08 AM:Idle
b   :10:11 AM:chatting
a   :10:10 AM:Logout
b   :10:12 AM:Logout

このようなものになります (クエリ期間として午前 10 時から午前 10 時 15 分の時間範囲を指定します)

name: State    :Duration
a   : chatting :2 Minutes 
a   : Idle     :2 Minutes
b   : chatting :1 Minute

これは SQL のみを使用して実行できますか?Informix バージョン 11.5 を使用しています

役に立ちましたか?

解決

単一の SQL ステートメントで実行できます。これがその証拠です。

設定

CREATE TEMP TABLE eventtable
(
    name CHAR(3) NOT NULL,
    time DATETIME HOUR TO MINUTE NOT NULL,
    state CHAR(8) NOT NULL
);

INSERT INTO eventtable(name, time, state) VALUES('a', '10:00', 'login');
INSERT INTO eventtable(name, time, state) VALUES('b', '10:05', 'login');
INSERT INTO eventtable(name, time, state) VALUES('a', '10:06', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('a', '10:08', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('b', '10:11', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('a', '10:10', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('b', '10:12', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:01', 'login');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:02', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:03', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:04', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:05', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:06', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:07', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:08', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:09', 'login');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:11', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:12', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:13', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:14', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:15', 'Logout');

正しいクエリ

条件に注意してください。結果テーブルでは、「ログイン」と最初の他のイベントの間の期間を除外する必要があります。さらに、「ログアウト」と次のイベント (おそらく「ログイン」) の間の期間を除外する必要があります。上のテーブル間の自己結合 名前 列、次に非対称結合 時間 列 (' を使用)<') イベントが時間順であることを保証します。NOT EXISTS サブ選択を使用すると、隣接するイベントのみが考慮されます。サブクエリで BETWEEN AND を使用するのは間違いです。エンドポイントが含まれるため、次の点が重要です。 r1.time そして r2.time は範囲から除外されます。そのバグを見つけるのに数分かかりました (クエリは実行されましたが行は返されませんでしたが、 なぜ?)!

SELECT r1.name, r1.state, r2.TIME - r1.TIME AS duration
    FROM eventtable r1, eventtable r2
    WHERE r1.name = r2.name
      AND r1.time < r2.time
      AND r1.state != 'login'
      AND r1.state != 'Logout'
      AND r1.time BETWEEN DATETIME(10:00) HOUR TO MINUTE
                      AND DATETIME(10:15) HOUR TO MINUTE
      AND r2.time BETWEEN DATETIME(10:00) HOUR TO MINUTE
                      AND DATETIME(10:15) HOUR TO MINUTE
      AND NOT EXISTS (SELECT 1 FROM eventtable r3
                            WHERE r3.time > r1.time AND r3.time < r2.time
                      AND r3.name = r1.name
                      AND r3.name = r2.name);

これにより、次のような答えが得られます。

name state      duration
a    chatting   0:02
a    Idle       0:02
b    chatting   0:01

c    chatting   0:01
c    Idle       0:01
c    Idle       0:01
c    Idle       0:01
c    chatting   0:01
c    Idle       0:01
c    chatting   0:01
c    Idle       0:01

「期間」の値は、INTERVAL HOUR TO MINUTE です。数分単位の値が必要な場合は、キャストで変換する必要があります (精度に 4 を使用すると、最大 1440 分または 1 日の間隔が許容されます)。より長い時間枠ではデータがあいまいになります):

(r2.time - r1.time)::INTERVAL MINUTE(4) TO MINUTE

または:

CAST (r2.time - r1.time AS INTERVAL MINUTE(4) TO MINUTE)

IBM Informix Dynamic Server (IDS) には、時定数の非常に詳細な表記法があります。標準 SQL では、型として TIME を使用し、値として TIME '10:00:00' を使用できますが、厳密な標準 SQL では秒が必要になります。IDS は、DATETIME HOUR TO MINUTE など、人々が望む正確な型を提供します。標準 SQL では INTERVAL MINUTE(4) と記述することもできます。「TO MINUTE」はオプションである必要があります。

間違ったクエリ

Ray Hidayat の回答に対する私のコメントの中で、検討中のイベントが連続していること、つまり間にイベントが存在しないことを確認するには、EXISTS サブクエリが必要であることを指摘しました。以下は、同じクエリの出力に開始時刻と終了時刻が追加され、EXISTS 句が欠落している (および 'duration' の名前が 'lapse' に変更された) です。

SELECT r1.name, r1.state, r2.TIME - r1.TIME AS lapse,
       r1.time AS start, r2.time AS end
    FROM eventtable r1, eventtable r2
    WHERE r1.name = r2.name
      AND r1.time < r2.time
      AND r1.state != 'login'
      AND r1.state != 'Logout'
      AND r1.time BETWEEN DATETIME(10:00) HOUR TO MINUTE
                      AND DATETIME(10:15) HOUR TO MINUTE
      AND r2.time BETWEEN DATETIME(10:00) HOUR TO MINUTE
                      AND DATETIME(10:15) HOUR TO MINUTE;

これにより、次のような答えが得られます。

name state     lapse start end
a    chatting   0:04 10:06 10:10
a    chatting   0:02 10:06 10:08
a    Idle       0:02 10:08 10:10
b    chatting   0:01 10:11 10:12
c    chatting   0:13 10:02 10:15
c    chatting   0:12 10:02 10:14
c    chatting   0:11 10:02 10:13
c    chatting   0:10 10:02 10:12
c    chatting   0:09 10:02 10:11
c    chatting   0:07 10:02 10:09
c    chatting   0:06 10:02 10:08
c    chatting   0:05 10:02 10:07
c    chatting   0:04 10:02 10:06
c    chatting   0:03 10:02 10:05
c    chatting   0:02 10:02 10:04
c    chatting   0:01 10:02 10:03
c    Idle       0:12 10:03 10:15
c    Idle       0:11 10:03 10:14
c    Idle       0:10 10:03 10:13
c    Idle       0:09 10:03 10:12
c    Idle       0:08 10:03 10:11
c    Idle       0:06 10:03 10:09
c    Idle       0:05 10:03 10:08
c    Idle       0:04 10:03 10:07
c    Idle       0:03 10:03 10:06
c    Idle       0:02 10:03 10:05
c    Idle       0:01 10:03 10:04
c    Idle       0:10 10:05 10:15
c    Idle       0:09 10:05 10:14
c    Idle       0:08 10:05 10:13
c    Idle       0:07 10:05 10:12
c    Idle       0:06 10:05 10:11
c    Idle       0:04 10:05 10:09
c    Idle       0:03 10:05 10:08
c    Idle       0:02 10:05 10:07
c    Idle       0:01 10:05 10:06
c    Idle       0:08 10:07 10:15
c    Idle       0:07 10:07 10:14
c    Idle       0:06 10:07 10:13
c    Idle       0:05 10:07 10:12
c    Idle       0:04 10:07 10:11
c    Idle       0:02 10:07 10:09
c    Idle       0:01 10:07 10:08
c    chatting   0:04 10:11 10:15
c    chatting   0:03 10:11 10:14
c    chatting   0:02 10:11 10:13
c    chatting   0:01 10:11 10:12
c    Idle       0:03 10:12 10:15
c    Idle       0:02 10:12 10:14
c    Idle       0:01 10:12 10:13
c    chatting   0:02 10:13 10:15
c    chatting   0:01 10:13 10:14
c    Idle       0:01 10:14 10:15

これは、ユーザー 'c' の適格な開始行がそれぞれ適格な終了行とどのように照合され、多くの偽のデータ行が得られるかを示しています。NOT EXISTS サブクエリは、時間ベースのクエリを扱う場合の一般的なテーマです。これらの操作に関する情報は、Snodgrass の「」で見つけることができます。SQL での時間指向アプリケーションの開発" (PDF は URL からオンラインで入手可能)、Date、Darwen と Lorentzos"時間データとリレーショナル モデル".

他のヒント

私はそれが唯一のSQLを使用して行うことができますかなり確信している、私が私が行っていたときに、それを編集します、あなたのためのクエリを思い付くために私にかなりの時間を取ることになるだろう。私は第1の和との句によって、単純なグループ(各エントリを取り、次のエントリにそれに参加し、時間差を見つけるために減算することによって行われる)各1にかかる時間を計算することだと思う基本的な手順は簡単になりますそれあなたが説明してきた形に。

編集:ここで私は

思い付きました
SELECT l.userid, l.state, SUM(t.minutes) AS duration
FROM Log l 
INNER JOIN (
    SELECT l1.id, (l2.time - l1.time) AS minutes
    FROM Log l1, Log l2
    WHERE l2.time == ( 
        -- find the next entry --
        SELECT TOP 1 ls.time
        FROM Log ls
        WHERE ls.Time > l1.Time && ls.userid = l1.userid
        ORDER BY ls.Time
    )
) t ON l.id == t.id
GROUP BY l.userid, l.state
ORDER BY l.userid

この半擬似コードである、あなたはおそらく、DATEDIFF関数を使用することがあります、私はすべてのテーブル名と物事を作って、あなただけの別から1時間を減算することはできません。そのほかにかかわらず、私はそれはそれの要点だと思います。私はあなたが少しのコードではほとんど何もすることができ、SQLは最も素晴らしい言語の一つだと思います。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top