Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get count of postitive and negative numbers per ID?

I'd like to get a count of negative values and positive values for each id.

Sample Fiddle

ID=1 has 2 positive and 0 negative transactions. etc.

 with trans_detail as 
 (
 select 1 as trans_id, 100 as trans_amount  from dual union all
 select 1 as trans_id, 200 as trans_amount  from dual union all
 select 2 as trans_id, -100 as trans_amount  from dual union all
 select 2 as trans_id, -300 as trans_amount  from dual union all
 select 3 as trans_id, 400 as trans_amount   from dual union all
 select 3 as trans_id, -500 as trans_amount  from dual
 )

 select trans_id,
       count(*) over (partition by trans_id) as pos_count,
       count(*) over (partition by trans_id) as neg_count        
from trans_detail
where trans_amount > 0
UNION
select trans_id,
       count(*) over (partition by trans_id) as pos_count,
       count(*) over (partition by trans_id) as neg_count        
from trans_detail
where trans_amount < 0;

Desired Result:

 ID   POS_COUNT   NEG_COUNT
---- ----------- -----------
 1    2           0 
 2    0           2
 3    1           1
like image 950
zundarz Avatar asked Aug 10 '15 16:08

zundarz


People also ask

How do you count positive and negative numbers in SQL?

To count number of positive and negative votes, you can use CASE statement along with aggregate function SUM().


4 Answers

Count 1 each time you see a positive or negative amount and sum that up.

select trans_id,
sum(case when trans_amount >=0 then 1 else 0 end) as pos_amt,
sum(case when trans_amount < 0 then 1 else 0 end) as neg_amt
from trans_detail
group by trans_id

http://sqlfiddle.com/#!4/db410/12

like image 164
duffn Avatar answered Nov 15 '22 10:11

duffn


select trans_id, 
nvl(sum(case when trans_amount < 0 then 1 end),0) as neg,
nvl(sum(case when trans_amount > 0 then 1 end),0) as pos
from trans_detail
group by trans_id

SQL Fiddle: http://sqlfiddle.com/#!4/db410/15

like image 33
Vamsi Prabhala Avatar answered Nov 15 '22 12:11

Vamsi Prabhala


Try this

select trans_id,
       Sum(case when trans_amount>=0 then 1 else 0 end) as pos_count,
       Sum(case when trans_amount<0 then 1 else 0 end) as neg_count,
from trans_detail
group by trans_id
like image 43
Madhivanan Avatar answered Nov 15 '22 11:11

Madhivanan


You can use a conditional count:

with trans_detail as 
 (
 select 1 as trans_id, 100 as trans_amount  from dual union all
 select 1 as trans_id, 200 as trans_amount  from dual union all
 select 2 as trans_id, -100 as trans_amount  from dual union all
 select 2 as trans_id, -300 as trans_amount  from dual union all
 select 3 as trans_id, 400 as trans_amount   from dual union all
 select 3 as trans_id, -500 as trans_amount  from dual
 )
select trans_id,
       count(case when trans_amount >= 0 then trans_id end) as pos_count,
       count(case when trans_amount < 0 then trans_id end) as neg_count        
from trans_detail
group by trans_id
order by trans_id;

  TRANS_ID  POS_COUNT  NEG_COUNT
---------- ---------- ----------
         1          2          0
         2          0          2
         3          1          1

Count ignores null values, so the implicit null 'else' to each case means those rows aren't counted. You can add else null if you prefer but it just makes it a bit longer. (I've included zero as 'positive' but you may want to ignore it completely as in your question; in which case just revert to > 0).

SQL Fiddle

You could also use the sign function, either in a case or a decode:

select trans_id,
       count(decode(sign(trans_amount), 1, trans_id)) as pos_count,
       count(decode(sign(trans_amount), -1, trans_id)) as neg_count        
from trans_detail
group by trans_id
order by trans_id;

SQL Fiddle; this ignores zero but you could include it in either decode if you wanted to.

like image 44
Alex Poole Avatar answered Nov 15 '22 12:11

Alex Poole