简体   繁体   中英

In MySQL how to rewrite a query using a case statement?

I have a MySQL table:

create table tbl (
  amount int
);

insert into tbl (amount) values (1);
insert into tbl (amount) values (2);
insert into tbl (amount) values (3);
insert into tbl (amount) values (4);

My goal is a report of how many values are in the following buckets, by using a case statment.

Bucket A: values 0-1
Bucket B: values 2-5
Bucket C: values 6-9

First lets try a simple query:

select "Bucket A" as Bucket, count(amount) "Count"
from tbl
where amount in (0,1)
union
select "Bucket B" as Bucket, count(amount) "Count"
from tbl
where amount in (2,3,4,5)
union
select "Bucket C" as Bucket, count(amount) "Count"
from tbl
where amount in (6,7,8,9);

Result:

+----------+-------+
| Bucket   | Count |
+----------+-------+
| Bucket A |     1 |
| Bucket B |     3 |
| Bucket C |     0 |
+----------+-------+

Results are perfect, but I want a case statement.
So I try this:

select 
sum(case when amount in (0,1) then 1 else 0 end) as "Bucket A",
sum(case when amount in (2,3,4,5) then 1 else 0 end) as "Bucket B",
sum(case when amount in (6,7,8,9) then 1 else 0 end) as "Bucket C"
from tbl;

Result:

+----------+----------+----------+
| Bucket A | Bucket B | Bucket C |
+----------+----------+----------+
|        1 |        3 |        0 |
+----------+----------+----------+

Values are correct, and great that I have a case statement, but problem is the values got pivoted.

How can I
1. use a case statement
2. have no pivot?

You can do this using aggregation:

select (case when amount in (0, 1) then 'Bucket A'
             when amount in (2, 3,4, 5) then 'Bucket B'
             when amount in (6, 7, 8, 9) then 'Bucket C'
        end) as bucket, count(*) as `count`
from tbl
where amount in (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
group by (case when amount in (0, 1) then 'Bucket A'
               when amount in (2,3,4,5) then 'Bucket B'
               when amount in (6,7,8,9) then 'Bucket C'
           end);

EDIT:

Digital Chris makes a very good point. This can be solved by using left outer join :

select (case when tbl.amount in (0, 1) then 'Bucket A'
             when tbl.amount in (2, 3,4, 5) then 'Bucket B'
             when tbl.amount in (6, 7, 8, 9) then 'Bucket C'
        end) as bucket, count(tbl.amount) as `count`
from (select 0 as amount union all
      select 2 as amount union all
      select 6 as amount
     ) throwaway left outer join
     tbl
     on throwaway.amount = tbl.amount
where tbl.amount in (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
group by (case when tbl.amount in (0, 1) then 'Bucket A'
               when tbl.amount in (2,3,4,5) then 'Bucket B'
               when tbl.amount in (6,7,8,9) then 'Bucket C'
           end);

Or, perhaps more clearly, by using the original query as a subquery:

select buckets.bucket, coalesce(`count`, 0) as `count`
from (select 'Bucket A' as bucket union all
      select 'Bucket B' union all
      select 'Bucket C'
     ) buckets left outer join
     (select (case when amount in (0, 1) then 'Bucket A'
                   when amount in (2, 3,4, 5) then 'Bucket B'
                   when amount in (6, 7, 8, 9) then 'Bucket C'
              end) as bucket, count(*) as `count`
      from tbl
      where amount in (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
      group by (case when amount in (0, 1) then 'Bucket A'
                     when amount in (2,3,4,5) then 'Bucket B'
                     when amount in (6,7,8,9) then 'Bucket C'
                 end)
     ) g
     on buckets.bucket = g.bucket;
select 
"Bucket A" as "Bucket", sum(case when amount in (0,1) then 1 else 0 end) as "Count" from tbl
UNION
select "Bucket B", sum(case when amount in (2,3,4,5) then 1 else 0 end) from tbl
UNION
select "Bucket C", sum(case when amount in (6,7,8,9) then 1 else 0 end) from tbl;

Like this? sqlfiddle

SELECT "Bucket A" AS Bucket ,
(SELECT SUM(CASE WHEN amount IN (0,1) THEN 1 ELSE 0 END) FROM tbl) AS "COUNT" 
UNION
SELECT "Bucket B" AS Bucket ,
(SELECT SUM(CASE WHEN amount IN (2,3,4,5) THEN 1 ELSE 0 END) FROM tbl) AS "COUNT" 
UNION
SELECT "Bucket C" AS Bucket ,
(SELECT SUM(CASE WHEN amount IN (6,7,8,9) THEN 1 ELSE 0 END) FROM tbl) AS "COUNT" 

sqlfiddle demo

Use a manufactured list of bucket names, then left join to the table:

select concat('Bucket ', b) bucket, count(amount) count
from (select 'A' as b union select 'B' union select 'C') a
left join tbl on b = 
  case when amount in (0, 1) then 'A'
       when amount in (2,3,4,5) then 'B'
       when amount in (6,7,8,9) then 'C' end
group by 1

This will produce a row with a zero count when no rows for the bucket are found.

See SQLFiddle

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM