2016-09-23 4 views
3

私は、テーブルに以下のデータを持っている:SQL回数連続した行

|event_id |starttime  |person_id|attended| 
|------------|-----------------|---------|--------| 
| 11512997-1 | 01-SEP-16 08:00 | 10001 | N  | 
| 11512997-2 | 01-SEP-16 10:00 | 10001 | N  | 
| 11512997-3 | 01-SEP-16 12:00 | 10001 | N  | 
| 11512997-4 | 01-SEP-16 14:00 | 10001 | N  | 
| 11512997-5 | 01-SEP-16 16:00 | 10001 | N  | 
| 11512997-6 | 01-SEP-16 18:00 | 10001 | Y  | 
| 11512997-7 | 02-SEP-16 08:00 | 10001 | N  | 
| 11512997-1 | 01-SEP-16 08:00 | 10002 | N  | 
| 11512997-2 | 01-SEP-16 10:00 | 10002 | N  | 
| 11512997-3 | 01-SEP-16 12:00 | 10002 | N  | 
| 11512997-4 | 01-SEP-16 14:00 | 10002 | Y  | 
| 11512997-5 | 01-SEP-16 16:00 | 10002 | N  | 
| 11512997-6 | 01-SEP-16 18:00 | 10002 | Y  | 
| 11512997-7 | 02-SEP-16 08:00 | 10002 | Y  | 

私は次のような結果を生成したい、連続して出現箇所の最大数=「N」atended返されます。

|person_id|consec_missed_max| 
| 1001 | 5    | 
| 1002 | 3    | 

これはどのようにOracle(またはANSI)SQLで行うことができますか?ありがとう!

編集:これまでのところ、私が試してみました

WITH t1 AS 
(SELECT t.person_id, 
    row_number() over(PARTITION BY t.person_id ORDER BY t.starttime) AS idx 
    FROM the_table t 
    WHERE t.attended = 'N'), 
t2 AS 
(SELECT person_id, MAX(idx) max_idx FROM t1 GROUP BY person_id) 
SELECT t1.person_id, COUNT(1) ct 
    FROM t1 
    JOIN t2 
    ON t1.person_id = t2.person_id 
GROUP BY t1.person_id; 
+0

分析関数私はまだそれを行う方法が完全にはわかりません。 – ubersnack

答えて

6

主な仕事は、因数分解サブクエリ "予備校" です。あなたは、分析関数にある程度精通しているようですが、それだけでは不十分です。このソリューションでは、いわゆる「タブビトサン」メソッドを使用して、1つ以上の次元で同じ特性を持つ連続する行のグループを作成します。この場合、シーケンスごとに異なるグループで連続するN行をグループ化する必要があります。これは、2人のROW_NUMBER()呼び出しの違いで行われます.1人は人のみで分割され、もう1人は人と出席者によって分割されます。必要に応じてGoogleの「タブビトサン」でアイデアの詳細を読む。

with 
    inputs (event_id, starttime, person_id, attended) as (
     select '11512997-1', to_date('01-SEP-16 08:00', 'dd-MON-yy hh24:mi'), 10001, 'N' from dual union all 
     select '11512997-2', to_date('01-SEP-16 10:00', 'dd-MON-yy hh24:mi'), 10001, 'N' from dual union all  
     select '11512997-3', to_date('01-SEP-16 12:00', 'dd-MON-yy hh24:mi'), 10001, 'N' from dual union all 
     select '11512997-4', to_date('01-SEP-16 14:00', 'dd-MON-yy hh24:mi'), 10001, 'N' from dual union all 
     select '11512997-5', to_date('01-SEP-16 16:00', 'dd-MON-yy hh24:mi'), 10001, 'N' from dual union all 
     select '11512997-6', to_date('01-SEP-16 18:00', 'dd-MON-yy hh24:mi'), 10001, 'Y' from dual union all 
     select '11512997-7', to_date('02-SEP-16 08:00', 'dd-MON-yy hh24:mi'), 10001, 'N' from dual union all 
     select '11512997-1', to_date('01-SEP-16 08:00', 'dd-MON-yy hh24:mi'), 10002, 'N' from dual union all 
     select '11512997-2', to_date('01-SEP-16 10:00', 'dd-MON-yy hh24:mi'), 10002, 'N' from dual union all 
     select '11512997-3', to_date('01-SEP-16 12:00', 'dd-MON-yy hh24:mi'), 10002, 'N' from dual union all 
     select '11512997-4', to_date('01-SEP-16 14:00', 'dd-MON-yy hh24:mi'), 10002, 'Y' from dual union all 
     select '11512997-5', to_date('01-SEP-16 16:00', 'dd-MON-yy hh24:mi'), 10002, 'N' from dual union all 
     select '11512997-6', to_date('01-SEP-16 18:00', 'dd-MON-yy hh24:mi'), 10002, 'Y' from dual union all 
     select '11512997-7', to_date('02-SEP-16 08:00', 'dd-MON-yy hh24:mi'), 10002, 'Y' from dual 
    ), 
     prep (starttime, person_id, attended, gp) as (
     select starttime, person_id, attended, 
       row_number() over (partition by person_id order by starttime) - 
        row_number() over (partition by person_id, attended 
             order by starttime) 
     from inputs 
    ), 
     counts (person_id, consecutive_absences) as (
     select person_id, count(*) 
     from prep 
     where attended = 'N' 
     group by person_id, gp 
    ) 
select person_id, max(consecutive_absences) as max_consecutive_absences 
from counts 
group by person_id 
order by person_id; 

OUTPUT:

PERSON_ID    MAX_CONSECUTIVE_ABSENCES 
---------- --------------------------------------- 
    10001          5 
    10002          3 
+0

完璧に働いて、ありがとう! – ubersnack

0

あなたがOracle 12cを使用している場合は使用できMATCH_RECOGNIZE

データ:

CREATE TABLE data AS 
SELECT * 
FROM (
with inputs (event_id, starttime, person_id, attended) as (
    select '11512997-1', to_date('01-SEP-16 08:00', 'dd-MON-yy hh24:mi'), 10001, 'N' from dual union all 
    select '11512997-2', to_date('01-SEP-16 10:00', 'dd-MON-yy hh24:mi'), 10001, 'N' from dual union all  
    select '11512997-3', to_date('01-SEP-16 12:00', 'dd-MON-yy hh24:mi'), 10001, 'N' from dual union all 
    select '11512997-4', to_date('01-SEP-16 14:00', 'dd-MON-yy hh24:mi'), 10001, 'N' from dual union all 
    select '11512997-5', to_date('01-SEP-16 16:00', 'dd-MON-yy hh24:mi'), 10001, 'N' from dual union all 
    select '11512997-6', to_date('01-SEP-16 18:00', 'dd-MON-yy hh24:mi'), 10001, 'Y' from dual union all 
    select '11512997-7', to_date('02-SEP-16 08:00', 'dd-MON-yy hh24:mi'), 10001, 'N' from dual union all 
    select '11512997-1', to_date('01-SEP-16 08:00', 'dd-MON-yy hh24:mi'), 10002, 'N' from dual union all 
    select '11512997-2', to_date('01-SEP-16 10:00', 'dd-MON-yy hh24:mi'), 10002, 'N' from dual union all 
    select '11512997-3', to_date('01-SEP-16 12:00', 'dd-MON-yy hh24:mi'), 10002, 'N' from dual union all 
    select '11512997-4', to_date('01-SEP-16 14:00', 'dd-MON-yy hh24:mi'), 10002, 'Y' from dual union all 
    select '11512997-5', to_date('01-SEP-16 16:00', 'dd-MON-yy hh24:mi'), 10002, 'N' from dual union all 
    select '11512997-6', to_date('01-SEP-16 18:00', 'dd-MON-yy hh24:mi'), 10002, 'Y' from dual union all 
    select '11512997-7', to_date('02-SEP-16 08:00', 'dd-MON-yy hh24:mi'), 10002, 'Y' from dual 
    ) 
SELECT * FROM inputs 
); 

と問合せ:

SELECT PERSON_ID, MAX(LEN) AS MAX_ABSENCES_IN_ROW 
FROM data 
MATCH_RECOGNIZE (
    PARTITION BY PERSON_ID 
    ORDER BY STARTTIME 
    MEASURES FINAL COUNT(*) AS len 
    ALL ROWS PER MATCH 
    PATTERN(a b*) 
    DEFINE b AS attended = a.attended 
) 
WHERE attended = 'N' 
GROUP BY PERSON_ID; 

出力:

"PERSON_ID","MAX_ABSENCES_IN_ROW" 
10001,5 
10002,3 

EDIT:@mathguyが指摘したように

それは以下のように書き換えることができます

ちょうどそれが使用に来るとき、私は、これまでにしようとしているものを追加
SELECT PERSON_ID, MAX(LEN) AS MAX_ABSENCES_IN_ROW 
FROM data 
MATCH_RECOGNIZE (
    PARTITION BY PERSON_ID 
    ORDER BY STARTTIME 
    MEASURES COUNT(*) AS len 
    PATTERN(a+) 
    DEFINE a AS attended = 'N' 
) 
GROUP BY PERSON_ID; 
+0

あまりにも複雑です。 'ALL ROWS PER MATCH'は必要ありません。それぞれのマッチはそのマッチの 'COUNT'を返すだけです。そして、 'WHERE'節は存在しません。代わりに、 'PATTERN'は' a + 'でなければならず、' DEFINE'節は 'DEFINE a AS attended = 'N''でなければなりません。これは、より効率的な解決策になります(計画を比較して示すように)。 – mathguy

+1

'COUNT(*)'の前に 'FINAL'という単語を削除するように編集しました。 'match per all rows'を返すと、' final() 'で修飾しない限り、 'count()'は解析関数のように振る舞います。しかし、あなたが**試合ごとに** **行を返すと(デフォルト)、 "実行中"対 "最終"はありません。実際には、 '1行1回 'で' final(something)'を使用すると、Oracleが構文エラーをスローしないことは実際は奇妙です。それはありませんが、「最終的に」はそこから外れています。 – mathguy

関連する問題