Let's say your query looks like this:
SELECT type,person,COUNT(*) `Count`
FROM mytable GROUP BY type,person WITH ROLLUP;
The NULL
values coming out can be substituted with something like this...
SELECT
IFNULL(type,'All Types') Type,
IFNULL(person,'All Persons') Person
COUNT(*) `Count`
FROM mytable GROUP BY type,person WITH ROLLUP;
Using IFNULL() will forcibly put those Text String in place of the NULL
for each level of the GROUP BY
. As an example, here are past posts where I actively substitute NULL
in my answer involving WITH ROLLUP
:
From these posts I have this example,
SELECT Statistic,DataSize "Data Size",IndexSize "Index Size",TableSize "Table Size"
FROM (SELECT IF(ISNULL(table_schema)=1,10,0) schema_score,
IF(ISNULL(engine)=1,10,0) engine_score, IF(ISNULL(table_schema)=1,
'ZZZZZZZZZZZZZZZZ',table_schema) schemaname,
IF(ISNULL(B.table_schema)+ISNULL(B.engine)=2,
"Storage for All Databases",IF(ISNULL(B.table_schema)+ISNULL(B.engine)=1,
CONCAT("Storage for ",B.table_schema),CONCAT(B.engine," Tables for ",
B.table_schema))) Statistic,
CONCAT(LPAD(REPLACE(FORMAT(B.DSize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') DataSize,
CONCAT(LPAD(REPLACE(FORMAT(B.ISize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') IndexSize,
CONCAT(LPAD(REPLACE(FORMAT(B.TSize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') TableSize FROM (SELECT table_schema,engine,
SUM(data_length) DSize,SUM(index_length) ISize,SUM(data_length+index_length) TSize
FROM information_schema.tables WHERE table_schema NOT IN
('mysql','information_schema','performance_schema') AND engine IS NOT NULL
GROUP BY table_schema,engine WITH ROLLUP) B,(SELECT 3 pw) A) AA
ORDER BY schemaname,schema_score,engine_score;
Here is the output from one of my client's DB Servers:
+------------------------------------+----------------------+----------------------+----------------------+
| Statistic | Data Size | Index Size | Table Size |
+------------------------------------+----------------------+----------------------+----------------------+
| MyISAM Tables for dev_oxygen | 0.000 GB | 0.000 GB | 0.000 GB |
| InnoDB Tables for dev_oxygen | 1.480 GB | 0.506 GB | 1.986 GB |
| Storage for dev_oxygen | 1.480 GB | 0.506 GB | 1.986 GB |
| MyISAM Tables for dumbpdb | 0.001 GB | 0.001 GB | 0.002 GB |
| InnoDB Tables for dumbpdb | 1.552 GB | 0.583 GB | 2.135 GB |
| Storage for dumbpdb | 1.553 GB | 0.584 GB | 2.137 GB |
| InnoDB Tables for duplicate_oxygen | 0.166 GB | 0.073 GB | 0.239 GB |
| Storage for duplicate_oxygen | 0.166 GB | 0.073 GB | 0.239 GB |
| InnoDB Tables for facebook_app | 0.000 GB | 0.000 GB | 0.000 GB |
| Storage for facebook_app | 0.000 GB | 0.000 GB | 0.000 GB |
| InnoDB Tables for generationo | 0.016 GB | 0.002 GB | 0.018 GB |
| Storage for generationo | 0.016 GB | 0.002 GB | 0.018 GB |
| InnoDB Tables for mantisbt | 0.000 GB | 0.000 GB | 0.001 GB |
| Storage for mantisbt | 0.000 GB | 0.000 GB | 0.001 GB |
| MyISAM Tables for oxygen | 0.003 GB | 0.002 GB | 0.005 GB |
| InnoDB Tables for oxygen | 1.771 GB | 0.739 GB | 2.510 GB |
| Storage for oxygen | 1.774 GB | 0.741 GB | 2.515 GB |
| Storage for All Databases | 4.990 GB | 1.907 GB | 6.897 GB |
+------------------------------------+----------------------+----------------------+----------------------+
18 rows in set (12.67 sec)
Notice I check the ISNULL() of each column and compare IF() function calls to produce a single column output. In your particular case, you are going to need one of these two queries
QUERY #1
SELECT
IF(ISNULL(type)=1,'Grand Total',
IF(ISNULL(person)=1,CONCAT(QUOTE(type),' Subtotal'),
CONCAT(QUOTE(type),' Subtotal for ',QUOTE(person)))
) Statistic,`Count`
FROM
(
SELECT type,person,COUNT(*) `Count`
FROM mytable GROUP BY type,person WITH ROLLUP
) A;
QUERY #2
SELECT
IF(type='AllDone','Grand Total',
IF(person='AllDone',CONCAT(QUOTE(type),' Subtotal'),
CONCAT(QUOTE(type),' Subtotal for ',QUOTE(person)))
) Statistic,`Count`
FROM
(
SELECT
IFNULL(type,'AllDone') type,
IFNULL(person,'AllDone') person,
COUNT(*) `Count`
FROM mytable GROUP BY type,person WITH ROLLUP
) A;
Here is some sample data:
DROP DATABASE IF EXISTS ryanodonnell;
CREATE DATABASE ryanodonnell;
USE ryanodonnell
CREATE TABLE mytable
(
id int not null auto_increment,
type varchar(20) not null,
person varchar(20) not null,
key type_person_index (type,person),
primary key (id)
);
INSERT INTO mytable (type,person) VALUES
('Type A','Person 1'),('Type A','Person 2'),('Type A','Person 3'),
('Type A','Person 5'),('Type A','Person 2'),('Type A','Person 3'),
('Type A','Person 2'),('Type A','Person 3'),('Type A','Person 1'),
('Type A','Person 5'),('Type A','Person 1'),('Type A','Person 5'),
('Type A','Person 3'),('Type A','Person 4'),('Type A','Person 5'),
('Type B','Person 1'),('Type B','Person 2'),('Type B','Person 3'),
('Type B','Person 2'),('Type B','Person 3'),('Type B','Person 4'),
('Type B','Person 3'),('Type B','Person 4'),('Type B','Person 5'),
('Type B','Person 4'),('Type B','Person 5'),('Type B','Person 4'),
('Type B','Person 3'),('Type B','Person 1'),('Type B','Person 3');
Here is that sample data loaded:
mysql> DROP DATABASE IF EXISTS ryanodonnell;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE DATABASE ryanodonnell;
Query OK, 1 row affected (0.00 sec)
mysql> USE ryanodonnell
Database changed
mysql> CREATE TABLE mytable
-> (
-> id int not null auto_increment,
-> type varchar(20) not null,
-> person varchar(20) not null,
-> key type_person_index (type,person),
-> primary key (id)
-> );
Query OK, 0 rows affected (0.08 sec)
mysql> INSERT INTO mytable (type,person) VALUES
-> ('Type A','Person 1'),('Type A','Person 2'),('Type A','Person 3'),
-> ('Type A','Person 5'),('Type A','Person 2'),('Type A','Person 3'),
-> ('Type A','Person 2'),('Type A','Person 3'),('Type A','Person 1'),
-> ('Type A','Person 5'),('Type A','Person 1'),('Type A','Person 5'),
-> ('Type A','Person 3'),('Type A','Person 4'),('Type A','Person 5'),
-> ('Type B','Person 1'),('Type B','Person 2'),('Type B','Person 3'),
-> ('Type B','Person 2'),('Type B','Person 3'),('Type B','Person 4'),
-> ('Type B','Person 3'),('Type B','Person 4'),('Type B','Person 5'),
-> ('Type B','Person 4'),('Type B','Person 5'),('Type B','Person 4'),
-> ('Type B','Person 3'),('Type B','Person 1'),('Type B','Person 3');
Query OK, 30 rows affected (0.00 sec)
Records: 30 Duplicates: 0 Warnings: 0
mysql>
Now, here is the output of Query #1:
mysql> SELECT
-> IF(ISNULL(type)=1,'Grand Total',
-> IF(ISNULL(person)=1,CONCAT(QUOTE(type),' Subtotal'),
-> CONCAT(QUOTE(type),' Subtotal for ',QUOTE(person)))
-> ) Statistic,`Count`
-> FROM
-> (
-> SELECT type,person,COUNT(*) `Count`
-> FROM mytable GROUP BY type,person WITH ROLLUP
-> ) A;
+----------------------------------+-------+
| Statistic | Count |
+----------------------------------+-------+
| 'Type A' Subtotal for 'Person 1' | 3 |
| 'Type A' Subtotal for 'Person 2' | 3 |
| 'Type A' Subtotal for 'Person 3' | 4 |
| 'Type A' Subtotal for 'Person 4' | 1 |
| 'Type A' Subtotal for 'Person 5' | 4 |
| 'Type A' Subtotal | 15 |
| 'Type B' Subtotal for 'Person 1' | 2 |
| 'Type B' Subtotal for 'Person 2' | 2 |
| 'Type B' Subtotal for 'Person 3' | 5 |
| 'Type B' Subtotal for 'Person 4' | 4 |
| 'Type B' Subtotal for 'Person 5' | 2 |
| 'Type B' Subtotal | 15 |
| Grand Total | 30 |
+----------------------------------+-------+
13 rows in set (0.27 sec)
mysql>
Now, here is the output of Query #2:
mysql> SELECT
-> IF(type='AllDone','Grand Total',
-> IF(person='AllDone',CONCAT(QUOTE(type),' Subtotal'),
-> CONCAT(QUOTE(type),' Subtotal for ',QUOTE(person)))
-> ) Statistic,`Count`
-> FROM
-> (
-> SELECT
-> IFNULL(type,'AllDone') type,
-> IFNULL(person,'AllDone') person,
-> COUNT(*) `Count`
-> FROM mytable GROUP BY type,person WITH ROLLUP
-> ) A;
+----------------------------------+-------+
| Statistic | Count |
+----------------------------------+-------+
| 'Type A' Subtotal for 'Person 1' | 3 |
| 'Type A' Subtotal for 'Person 2' | 3 |
| 'Type A' Subtotal for 'Person 3' | 4 |
| 'Type A' Subtotal for 'Person 4' | 1 |
| 'Type A' Subtotal for 'Person 5' | 4 |
| 'Type A' Subtotal | 15 |
| 'Type B' Subtotal for 'Person 1' | 2 |
| 'Type B' Subtotal for 'Person 2' | 2 |
| 'Type B' Subtotal for 'Person 3' | 5 |
| 'Type B' Subtotal for 'Person 4' | 4 |
| 'Type B' Subtotal for 'Person 5' | 2 |
| 'Type B' Subtotal | 15 |
| Grand Total | 30 |
+----------------------------------+-------+
13 rows in set, 2 warnings (0.00 sec)
mysql>
Give it a Try !!!
Best Answer
First, let me explain why your code doesn't work when
A
orB
isNULL
by formatting your code to show that you have 2CASE
expressions, one inside the other:If
A > B
is true, the result is(CF1=3)
. If that isn't true, and ifA < B
is true, the result is(CF1=0)
. Otherwise, if neitherA>B
norA<B
is true, the result is(CF1=1)
. This last case (theELSE - ELSE
part) covers any remaining case which means whenA = B
orA is null
orB is null
.So to solve the issue, you need to explicitly compare
A = B
or compareA
andB
withNULL
, to differentiate. As a result theCASE
expression should have 4 parts, not 3. And (irrelevent to the issue) we don't need two nested expressions, we can have the result we want with one expression.And I assume that you want the result to be
3, 1, etc
and the(CF1=3)
is just pseudo-code.Note that the
ELSE NULL
is not needed as it is the default forCASE
expressions. If you want, you can have even more strict and clear with your intentions code: