2017-09-08 10 views
2

私は3つの列(lending_id int, installment_n serial int, status text)のテーブルを持っていて、各貸出IDに対して最大の隙間WAITING_PAYMENT (status)を取得する方法を知りました。最高連続出現の合計

lending_id | installment_n | status 
71737 1 PAID 
71737 2 PAID 
71737 3 PAID 
71737 4 PAID 
71737 5 PAID 
71737 6 WAITING_PAYMENT 
71737 7 WAITING_PAYMENT 
71737 8 WAITING_PAYMENT 
71737 9 WAITING_PAYMENT 
71737 10 WAITING_PAYMENT 
71737 11 WAITING_PAYMENT 
71737 12 WAITING_PAYMENT 
71737 13 WAITING_PAYMENT 
71737 14 WAITING_PAYMENT 
71737 15 WAITING_PAYMENT 
71737 16 WAITING_PAYMENT 
71737 17 WAITING_PAYMENT 
71737 18 WAITING_PAYMENT 
71737 19 WAITING_PAYMENT 
71737 20 WAITING_PAYMENT 
71737 21 WAITING_PAYMENT 
354226 1 PAID 
354226 2 PAID 
354226 3 WAITING_PAYMENT 
354226 4 WAITING_PAYMENT 
354226 5 WAITING_PAYMENT 
354226 6 WAITING_PAYMENT 
354226 7 PAID 
354226 8 WAITING_PAYMENT 
354226 9 WAITING_PAYMENT 
354226 10 WAITING_PAYMENT 
354226 11 WAITING_PAYMENT 
354226 12 WAITING_PAYMENT 
354226 13 WAITING_PAYMENT 
354226 14 WAITING_PAYMENT 
354226 15 WAITING_PAYMENT 

私が取得する方法を疑問に思う:次の例について

lending_id | count 
71737  | 16 
354226  | 8 

71737のは21(16) および354226の間のギャップのために設置6から検討するため8および15(8)。

答えて

1

row_number()を模倣したアプローチで、ウィンドウ関数をサポートしていないMySQLバージョンで動作します(ウィンドウ関数はMySQL v8.xに組み込まれる予定です)。

このアプローチの結果は、単なるカウントだけではなく、最も長いシーケンスについてのより多くの事実を明らかにするでしょう。詳細は以下の結果を参照してください。

SQL Fiddle

のMySQL 5.6スキーマのセットアップ

CREATE TABLE Table1 
    (`lending_id` int, `installment_n` int, `status` varchar(15)) 
; 

INSERT INTO Table1 
    (`lending_id`, `installment_n`, `status`) 
VALUES 
    (71737, 1, 'PAID'), 
    (71737, 2, 'PAID'), 
    (71737, 3, 'PAID'), 
    (71737, 4, 'PAID'), 
    (71737, 5, 'PAID'), 
    (71737, 6, 'WAITING_PAYMENT'), 
    (71737, 7, 'WAITING_PAYMENT'), 
    (71737, 8, 'WAITING_PAYMENT'), 
    (71737, 9, 'WAITING_PAYMENT'), 
    (71737, 10, 'WAITING_PAYMENT'), 
    (71737, 11, 'WAITING_PAYMENT'), 
    (71737, 12, 'WAITING_PAYMENT'), 
    (71737, 13, 'WAITING_PAYMENT'), 
    (71737, 14, 'WAITING_PAYMENT'), 
    (71737, 15, 'WAITING_PAYMENT'), 
    (71737, 16, 'WAITING_PAYMENT'), 
    (71737, 17, 'WAITING_PAYMENT'), 
    (71737, 18, 'WAITING_PAYMENT'), 
    (71737, 19, 'WAITING_PAYMENT'), 
    (71737, 20, 'WAITING_PAYMENT'), 
    (71737, 21, 'WAITING_PAYMENT'), 
    (354226, 1, 'PAID'), 
    (354226, 2, 'PAID'), 
    (354226, 3, 'WAITING_PAYMENT'), 
    (354226, 4, 'WAITING_PAYMENT'), 
    (354226, 5, 'WAITING_PAYMENT'), 
    (354226, 6, 'WAITING_PAYMENT'), 
    (354226, 7, 'PAID'), 
    (354226, 8, 'WAITING_PAYMENT'), 
    (354226, 9, 'WAITING_PAYMENT'), 
    (354226, 10, 'WAITING_PAYMENT'), 
    (354226, 11, 'WAITING_PAYMENT'), 
    (354226, 12, 'WAITING_PAYMENT'), 
    (354226, 13, 'WAITING_PAYMENT'), 
    (354226, 14, 'WAITING_PAYMENT'), 
    (354226, 15, 'WAITING_PAYMENT') 
; 

クエリ1

select lending_id, status, start_at_inst, end_at_inst, inst_count 
from (
     select IF(@prev_value=lending_id, @rn:[email protected]+1 , @rn:=1) AS rn 
      , lending_id, status, start_at_inst, end_at_inst, inst_count 
      , @prev_value := lending_id z 
     from (
      select lending_id 
        , status 
        , grpby 
        , min(installment_n) start_at_inst 
        , max(installment_n) end_at_inst 
        , (max(installment_n) + 1) - min(installment_n) inst_count 
      from (
       select 
         IF(@prev_value=concat_ws(',',lending_id,status), @rn:[email protected]+1 , @rn:=1) AS rn 
         , t.* 
         , installment_n - @rn grpby 
         , @prev_value := concat_ws(',',lending_id,status) z 
       from Table1 t 
       cross join (
        select @rn := 0 , @prev_value := '' 
        ) vars 
       order by lending_id, status,installment_n ASC 
       ) d1 
      group by lending_id, status, grpby 
     ) d2 
     cross join (
      select @rn := 0 , @prev_value := '' 
     ) vars 
     order by lending_id, inst_count DESC 
    ) d3 
where rn = 1 

Results

| lending_id |   status | start_at_inst | end_at_inst | inst_count | 
|------------|-----------------|---------------|-------------|------------| 
|  354226 | WAITING_PAYMENT |    8 |   15 |   8 | 
|  71737 | WAITING_PAYMENT |    6 |   21 |   16 | 

のMySQLのV8.xは、製品リリースになるまで、あなたはROW_NUMBER()を使用することはできませんけれども。しかし、すでにdbをサポートしているユーザーやMySQLユーザーが利用できる場合は、@variableアプローチよりも効率的であると考えるrow_number()を使用するのと同じアプローチがあります。

select 
     lending_id, status, start_at_inst, end_at_inst, inst_count 
from (
select 
     lending_id 
     , status 
     , grpby 
     , min(installment_n) start_at_inst 
     , max(installment_n) end_at_inst 
     , (max(installment_n) + 1) - min(installment_n) inst_count 
     , row_number() over(partition by lending_id order by (max(installment_n) + 1) - min(installment_n) DESC) rn 
from (
    select 
      t.* 
      , installment_n - row_number() over(partition by lending_id, status order by installment_n) grpby 
    from Table1 t 
    ) d1 
group by 
     lending_id, status, grpby 
    ) d2 
where rn = 1 
; 

結果:

lending_id | status   | start_at_inst | end_at_inst | inst_count 
---------: | :-------------- | ------------: | ----------: | ---------: 
     71737 | WAITING_PAYMENT |    6 |   21 |   16 
    354226 | WAITING_PAYMENT |    8 |   15 |   8 

dbfiddle(mariadb_10.2)here

2

あなたは、相関サブクエリといくつかの追加のロジックを使用することができます。

select lending_id, max(cnt) 
from (select lending_id, t.next_in, count(*) as cnt 
     from (select t.*, 
        (select min(t2.installment_n) 
        from t t2 
        where t2.lending_id = t.lending_id and t2.installment_n > t.installment_n and 
          t2.status <> 'WAITING_PAYMENT' 
        ) as next_in 
      from t 
      where t.status = 'WAITING_PAYMENT' 
      ) t 
     group by lending_id, t.next_in 
    ) lt 
group by lending_id; 

このしくみを教えてください。最も内側のサブクエリは、WAITING_PAYMENTでない次の割賦番号を取得します。ない場合はNULLです。これは、シーケンシャルWAITING_PAYMENTレコードのすべてのグループを識別します。

中間サブクエリは、各グループの番号を計算します。外部クエリは最大値をとります。

+0

完璧。 –

+0

最後の行が「有料」のときに問題が発生しました。ここで私を助けてくれますか? https://stackoverflow.com/questions/46897764/getting-biggest-interval-of-rows-with-same-value –

+0

@ JulinhodaAdelaide。 。 。何が問題ですか?何も明らかではない。 –

1

SQL下記のザ・トリックやファッションを読み、理解しやすい行う必要があります任意のさらなる明確化のために

select t1.lending_id, max(t1.installment_n) - min(t1.installment_n) as count 
from table t1 
where t1.status = 'WAITING_PAYMENT' 
and t1.installment_n > 
    (SELECT max(t2.installment_n) FROM table t2 where t2.lending_id = t1.lending_id and t2.status = 'PAID') 
group by lending_id; 

を掲載することを躊躇しないでください。

Ted。

+0

この作業セットは絶対に完璧です。 Thannks。 –

+0

クール!喜んで助けになった。しかし、今答えてマークすることを忘れないでください! ;) –

+0

@JulinhodaAdelaide - 実際には、そうではありません、[例のフィドル](http://sqlfiddle.com/#!9/78c777/1/0)(7を返す、期待された8ではない)を参照してください。しかし、より大きな問題は、「最新の」「PAID」イベントの後に「WAITING_PAYMENT」シーケンスのみを考慮していることです。これは_最長シーケンスではないかもしれません。サンプルデータから追加の行を削除すると、4より下に下がります。 –

関連する問題