2016-04-07 27 views
0

Postgresql db hakkında user_id, item_id, başarılı (bool) ve created_at sütunları içeren bir puan tablosum var.SQL sayımı ve koşullu gruplandırma

Her kullanıcı ve her öğe için başarılı öğelerin sayısını saymak istiyorum (başarılı olduğunda = 't'). Ama sadece son başarısızlıktan sonra başarılı olanı saymak istiyorum.

Aşağıdaki kodu başarılı olmadan denerim.

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

verileri: (kullanıcı 12)

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 

Excepted sonucu:

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

Örnek tablo verilerini ve beklenen sonucu ekler misiniz? – jarlh

+0

Bir örnek ekliyorum. – skyporter

cevap

2

Bir NOT EXISTS koşulu ekleyin. Yalnızca daha sonra yanlış sıraya sahip olmayan gerçek satırların sayıldığından emin olur.

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

Mükemmel! Bir charme gibi çalışır. Teşekkürler. – skyporter

0

için where madde satır filtre edilmelidir. succeeded sadece 'f' veya 't' değerlerini aldığını varsayarsak:

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; 

Not: Bu 0 değerlerini filtreler. Bunun yerine join kullanarak hepsini alabilirsiniz:

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 o zaman dış sorguya bir where madde eklemek veya koşullu toplamını kullanabilirsiniz 'f' dışındaki değerler alabilir.