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 !!!