2012-01-11 3 views
2

Iは、ユーザアクションのテーブルを持って、それぞれが関連するユーザ、タイプ、およびタイムスタンプを有するため、以前のOPENと一致すべきです。簡単な例を次に示します:マッチングユーザアクション:各CLOSEは、所与のユーザ

TABLE USER_ACTIONS 
------------------------ 
USER | TYPE | TIMESTAMP 
------------------------ 
a | OPEN | 0 
b | OPEN | 1 
a | CLOSE | 2 
a | OPEN | 3 
b | CLOSE | 4 
a | CLOSE | 4 
a | OPEN | 5 <-- "orphaned" OPEN, with no corresponding CLOSE. Should be ignored. 
c | OPEN | 3 
c | CLOSE | 5 
a | OPEN | 6 
a | CLOSE | 8 

私はこの中からトランザクション時間のリストを取得したいと思います。特定のユーザーの場合、各CLOSEは以前のOPENと一致する必要があります。私は順序を気にしない

USER | TRANSACTION_TIME 
----------------------- 
a | 2 
b | 3 
a | 1 
c | 2 
a | 2 

:私が好きな

結果は次のようになります。

私はこれをプログラムで行うことが可能ですが、それはいくつかの巧妙なSQLで行うことが可能であることを知っていますか?

UPDATE:

はプログラムでこれを行うには、一般的な考え方は、することです...

  1. はTIMESTAMPの降順で注文、 "CLOSE" すべてのアクションを選択します。
  2. リスト内の各自について、同じユーザーが行った以前の「OPEN」アクションを探してみてください。 TIMESTAMP DESCで結果をソートし、そのペアについて1.
  3. にそれらを制限し、時間差を計算し、その結果を出力リレー、「CLOSE」アクションTIMESTAMP前になるようにTIMESTAMPを制限します。ここで

は、いくつかの擬似コードだが、本当に私はこの巧妙んSQLたい:

for each CLOSE_ACTION IN ("SELECT USER, TYPE, TIMESTAMP FROM USER_ACTIONS WHERE TYPE='CLOSE' ORDER BY TIMESTAMP DESC;") { 
    OPEN_ACTION = "SELECT USER, TYPE, TIMESTAMP FROM USER_ACTIONS 
        WHERE TYPE='OPEN' 
        AND USER='<CLOSE_ACTION.USER>' 
        AND TIMESTAMP='<CLOSE_ACTION.TIMESTAMP>' 
        ORDER BY TIMESTAMP DESC 
        LIMIT 1"; 
    if OPEN_ACTION != empty/null then { 
     print CLOSE_ACTION.USER, CLOSE_ACTION.TIMESTAMP - OPEN_ACTION.TIMESTAMP; 
    } 
} 
+0

あなたは*常に*開いているCLOSEを持っていることを知っていますか?あるいは、ユーザのための順序は、「OPEN、OPEN、CLOSE、OPEN、OPEN、CLOSE、CLOSE」などである可能性がありますか?データが*完全にクリーン*でない場合、そのようなシナリオをどのように処理したいのか分かりますか? *(開き繰り返したが、それは本当にであるかのように 'CLOSE、CLOSE'を扱う無視' CLOSE、OPEN、CLOSE'、例えば?)* – MatBailie

+0

良い質問:残念ながら、すべてのOPENのためCLOSEありません。私はそれを反映するために私のテーブルを更新します。そのような場合は、孤立したOPENが無視され、カウントされないようにしたいと思います。 –

+0

あなたの例では、パターンが 'OPEN、CLOSE、CLOSE'であれば、どのcloseを無視すべきですか?私の答えは現在、2回目の「CLOSE」を無視し、残りの部分は満たしています。 – MatBailie

答えて

1

これは、前のイベントが開かれている場合にのみ、各CLOSEイベントを受け取り、先行するイベントに一致します。

SELECT 
    OPEN.user, 
    OPEN.transaction_time 
    CLOSE.transaction_time 
FROM 
    user_actions as CLOSE 
INNER JOIN 
    user_actions as OPEN 
    ON OPEN.user = CLOSE.user 
    AND OPEN.transaction_time = (SELECT MAX(transaction_time) FROM user_action 
           WHERE user = CLOSE.user 
           AND transaction_time < CLOSE.transaction_time 
           AND type='OPEN') 
WHERE 
    CLOSE.type = 'CLOSE' 
+0

これは非常に、非常に近いようですが、私はそれをうまく動作させることはできません。私はそれをしつこいつづけるつもりです。私はあなたの答えを編集することがあります。 –

+0

ブーム。作品!ありがとうございました! –

+0

編集後、これは 'OPEN、CLOSE、CLOSE'の場合の振る舞いを変更しますが、現在は両方とも参照が使用され、両方が同じOPENを振り返ります。 – MatBailie

0

試してみてください。

select user, 
     timestamp, 
     (select min(timestamp) 
     from user_actions u 
     where a.user = u.user and 
       u.type = 'CLOSE' and 
       u.timestamp > a.timestamp) - timestamp 
from user_actions a 
where type = 'OPEN' 

は(常に各オープンのためのマッチング近いがあるだろうと想定し。)

+0

'とu.timestamp> a.timestamp'? – MatBailie

+0

@Dems:ダハ!ありがとうございました! –

0

以下のクエリは疑問が提起のために正常に動作します。私は私のローカルマシンでそれを実行し、それは正常に動作するようです。

select u1.user_name ,u2.timestamp- max(u1.timestamp) difference 
from user_actions u1,user_actions u2 
where u1.type = 'OPEN' and 
u2.type = 'CLOSE' and 
u1.timestamp <u2.timestamp and u1.user_name = u2.user_name 
group by (u1.user_name , u2.timestamp); 
関連する問題