2016-11-23 6 views
3

特定の一連のイベントを満たすUserIDのレコードを取得しようとしています。ユーザーがJOINを持っていて、それに続くCANCELとその後のJOINがある場合、結果セットでそれらを戻したいと思います。必要に応じて、一度に1日または数日にこのクエリを実行する必要があります。イベントの特定のシーケンスを満たす行を返すにはどうすればよいですか?

次の表は、シーケンスを満たしていないユーザーIDの例を示しています。

+--------+--------+---------------------+------------+------------------+ 
| rownum | UserID |  Timestamp  | ActionType | Return in query? | 
+--------+--------+---------------------+------------+------------------+ 
|  1 | 12345 | 2016-11-01 08:25:39 | JOIN  | yes    | 
|  2 | 12345 | 2016-11-01 08:27:00 | NULL  | yes    | 
|  3 | 12345 | 2016-11-01 08:28:20 | DOWNGRADE | yes    | 
|  4 | 12345 | 2016-11-01 08:31:34 | NULL  | yes    | 
|  5 | 12345 | 2016-11-01 08:32:44 | CANCEL  | yes    | 
|  6 | 12345 | 2016-11-01 08:45:51 | NULL  | yes    | 
|  7 | 12345 | 2016-11-01 08:50:57 | JOIN  | yes    | 
|  1 | 9876 | 2016-11-01 16:05:42 | JOIN  | yes    | 
|  2 | 9876 | 2016-11-01 16:07:33 | CANCEL  | yes    | 
|  3 | 9876 | 2016-11-01 16:09:09 | JOIN  | yes    | 
|  1 | 56565 | 2016-11-01 18:15:16 | JOIN  | no    | 
|  2 | 56565 | 2016-11-01 19:22:25 | CANCEL  | no    | 
|  3 | 56565 | 2016-11-01 20:05:05 | CANCEL  | no    | 
|  1 | 34343 | 2016-11-01 05:32:56 | JOIN  | no    | 
+--------+--------+---------------------+------------+------------------+ 

私はギャップや島々をよく読んで、そして私が達成しようとしているものを周りに踊る複雑なフォーラムの投稿のすべての種類を見てきました。

SELECT 
    ROW_NUMBER() OVER (PARTITION BY UserID ORDER BY tmsmp) rownum 
    ,UserID 
    ,tmstmp 
    ,ActionType 
FROM 
    t 
    INNER JOIN (
       SELECT UserID 
       FROM t 
       WHERE tmstmp BETWEEN '2016-11-20 00:00:01' AND '2016-11-20 11:59:59' 
       GROUP BY UserID 
       HAVING COUNT(*) >= 2 
       ) AS sub ON t1.UserID = sub.UserID 

がご入力いただき、ありがとうございます:

現在、私が行うことができるよすべては私が必要とするシーケンス・ロジック上の制約なしに、レコードの1日分を見ています!

+0

3つのレコードを順番に並べる必要がありますか?つまり、ギャップがあるか、ギャップのないジョイン/キャンセル/ジョインが必要なのでしょうか? –

+0

返された行は、テーブルから引き抜かれる連続した希望の順序である必要はありませんが、将来のニーズに対応するために両方の出力を達成するというあなたの考えを知りたいと思うでしょう。ありがとう! – psrpsrpsr

+0

ちょっと面白いですが、もう1つの解決策として、 'select * from(userid、string_agg(actiontype、 '、タイムスタンプ順)/ * filter(actiontypeはnullではありません)*/'%JOIN、CANCEL、JOIN%'; ' – Abelisto

答えて

1

をクエリあなたが与えた情報でできる限り最善を尽くしますが、ソーステーブルの外観は少し不明です。上の表を(名前なしで)表示しますが、サンプルクエリで2つの異なる表を参照してください...何が起こっているのかを見るのは少し難しいです。

だから私はこれを処理する方法を、最初の時点でそれをユーザ

select distinct userid 
    from   t first_join 
     inner join t cancel 
       on first_join.tmstmp < cancel.tmstp 
       and first_join.userid = cancel.userid 
     inner join t.second_join 
       on second_join.tmstmp > cancel.tmstp 
       and second_join.userid = cancel.userid 
where first_join.actiontype = 'JOIN' 
    and cancel.actiontype = 'CANCEL' 
    and second_join.actiontype = 'JOIN' 

を識別された後、私はtという名前の、単一のテーブルを仮定します、そして必要に応じてあなたが調整することができます...

それらのユーザーのすべてのレコードを取得することができます

SELECT * 
    FROM T 
WHERE USERID IN (
    select distinct userid 
     from   t first_join 
      inner join t cancel 
        on first_join.tmstmp < cancel.tmstp 
        and first_join.userid = cancel.userid 
      inner join t.second_join 
        on second_join.tmstmp > cancel.tmstp 
        and second_join.userid = cancel.userid 
    where first_join.actiontype = 'JOIN' 
     and cancel.actiontype = 'CANCEL' 
     and second_join.actiontype = 'JOIN' 
    ) 
+0

こんにちはマーク、私は 't1'から 't'に私のサンプルクエリを編集しました - それは、メインのWHERE句とINNER JOINの両方で同じテーブルを参照しています。 – psrpsrpsr

1

あなただけlag()lead()またはそれらの組み合わせを使用して、レコードがギャップのない順序であることを意味と仮定すると:ギャップが許可されている場合

select distinct userId 
from (select t.*, 
      lag(ActionType) over (partition by userId order by tmstamp) as prev_at, 
      lead(ActionType) over (partition by userId order by tmstamp) as next_at, 
     from t 
    ) t 
where ActionType = 'Cancel' and prev_at = 'Join' and next_at = 'Join'; 

、あなたは異なってこれを行うことができます。

select distint userid 
from t 
where ActionType = 'Cancel' and 
     exists (select 1 
       from t t2 
       where t2.userId = t.userId and 
        t2.at = 'Join' and 
        t2.tmstamp < t.tmstamp 
      ) and 
     exists (select 1 
       from t t2 
       where t2.userId = t.userId and 
        t2.at = 'Join' and 
        t2.tmstamp > t.tmstamp 
      ); 
4

あなたがLEAD()使用することができます。私のサンプルでは

SELECT * FROM (
    SELECT t.* , 
      LAG(t.ActionType,1) OVER(PARTITION BY t.userid ORDER BY t.timestamp) AS LAST_ACTION, 
      LAG(t.ActionType,2) OVER(PARTITION BY t.userid ORDER BY t.timestamp) AS LAST_ACTION2, 
      LEAD(t.ActionType,1) OVER(PARTITION BY t.userid ORDER BY t.timestamp) AS NEXT_Action, 
      LEAD(t.ActionType,2) OVER(PARTITION BY t.userid ORDER BY t.timestamp) AS NEXT_Action2 
    FROM YourTable t 
    WHERE tmstmp BETWEEN <Start> AND <End>) 
WHERE (t.actionType = 'JOIN' AND 
     t.NEXT_Action = 'Cancel' AND 
     t.NEXT_Action2 = 'JOIN') 
    OR (t.LAST_ACTION= 'JOIN' AND 
     t.actionType= 'Cancel' AND 
     t.NEXT_Action = 'JOIN') 
    OR (t.LAST_ACTION2= 'JOIN' AND 
     t.LAST_ACTION = 'Cancel' AND 
     t.actionType= 'JOIN') 
+0

sagiのようなアクションは、JOIN> CANCEL> JOINオカレンスの間に発生する可能性のある不連続な行を考慮しますか?たとえば、上記の私のサンプルコードでは、UserIDは1行目にJOIN、5行目にCANCEL、7行目にJOINを持っています。これは、次の行だけをオフセットパラメータリード関数のあなたの洞察に感謝します。 – psrpsrpsr

+0

@psrpsrpsr理解していますが、今試してみるか分かりません:) – sagi

+0

JOIN、次にキャンセル、JOINの間にActionType値をいくつでも設定できます。これらの3つのシーケンスが連続して発生する限り、20行にわたって不連続に発生するかどうかは関係ありません。また、3行にわたって連続して発生します。私の質問は、1と2のLEAD関数のオフセットパラメータにより、最初のJOINから1行または2行離れたものだけにソリューションを制限するかどうかです。私は必要に応じてもっと多くの例を提供しています。ありがとう!! – psrpsrpsr

関連する問題