2016-04-07 21 views
0

私のpostgresql dbには、user_id、item_id、succeeded(bool)およびcreated_atという列のスコア表があります。条件付きのSQLカウントとグループ化

各ユーザーと各アイテム(succeeded = 't')の成功アイテムの数をカウントします。しかし、私は最後の失敗後に発生した成功アイテムを数えたいだけです。

私は以下のコードを成功させることなく試してみます。

SELECT COUNT(*), item_id 
FROM score 
WHERE score.succeeded = 't' AND user_id = XX 
GROUP BY score.item_id 
HAVING MAX(score.created_at) > score.created_at AND score.succeeded = 'f' 

exemple

データ:

user_id | item_id | succeeded | created_at 
------------------------------------------ 
12  | 1  | true  | 2016-04-01 
12  | 1  | false  | 2016-04-02 
12  | 1  | true  | 2016-04-03 

12  | 2  | true  | 2016-04-01 
12  | 2  | true  | 2016-04-02 
12  | 2  | true  | 2016-04-03 

12  | 3  | true  | 2016-04-01 
12  | 3  | true  | 2016-04-02 
12  | 3  | false  | 2016-04-03 

除外結果(ユーザ12):

item_id | succeeded_count 
------------------------- 
1  | 1 
2  | 3 
3  | 0 
+0

サンプルテーブルのデータと予想される結果を追加できますか? – jarlh

+0

私は例を追加します。 – skyporter

答えて

2

NOT EXISTSの条件を追加します。それは、後の偽の行を持たない真の行だけがカウントされることを保証する。

SELECT COUNT(*), s1.item_id 
FROM score s1 
WHERE score.succeeded = 't' 
    AND s1.user_id = XX 
    AND NOT EXISTS (select 1 from score s2 
        where s2.user_id = s1.user_id 
        and s2.item_id = s1.item_id 
        and s2.succeeded = 'f' 
        and s2.created_at > s1.created_at) 
GROUP BY s1.item_id 
+0

完璧!それはチャーミーのように働く。ありがとう。 – skyporter

0

あなたはwhere句の行をフィルタリングしなければなりません。

select s.item_id, count(*) 
from score s 
where s.created_at > (select max(s2.created_at) 
         from score s2 
         where s2.item_id = s.item_id and s2.succeeded = 'f' 
        ) 
group by s.item_id; 

注:これは0の値を除外しますsucceededだけ'f''t'の値をとると仮定すると。代わりにjoinを使用してそれらのすべてを取得することができます:

select s.item_id, count(s2.item_id) 
from scores s left join 
    (select item_id, max(created_at) maxca 
     from scores 
     where succeeded = 'f' 
     group by item_id 
    ) ss 
    on s.item_id = ss.item_id and s.created_at >= ss.maxca 
group by item_id; 

succeeded'f'以外の値を取ることができるなら、あなたは、外側のクエリにwhere句を追加したり、条件付きの集約を使用することができます。