I have tried to use IFNULL to replace the NULL fields returned by ROLLUP for subtotals and totals but it doesn't appear to be working.
Query:
select IFNULL(usergroups.name, 'GROUP') AS DEALER,
IFNULL(users.name, 'TOTAL') AS SERVICE_ADVISOR,
COUNT(DISTINCT vcrs.uid) AS COMPLETED,
..........
..........
and vcrs.vcrSubStatus = 4
group by DEALER, SERVICE_ADVISOR with ROLLUP;
Output:
DEALER SERVICE_ADVISOR COMPLETED IDENTIFIED AUTHORISED
Aston Martin Chris 3 664.56 0
Aston Martin Graham 6 0 0
Aston Martin (NULL) 15 664.56 0
Bentley Sukraj 1 0 0
Bentley Terry 4 0 0
Bentley (NULL) 5 0 0
Jaguar Emma 10 2448 1224
Jaguar Paul 1 0 0
Jaguar Simon 7 2754 918
Jaguar (NULL) 18 5202 2142
(NULL) (NULL) 2611 96591.62 42130.14
Desired Output:
DEALER SERVICE_ADVISOR COMPLETED IDENTIFIED AUTHORISED
Aston Martin Chris 3 664.56 0
Aston Martin Graham 6 0 0
Aston Martin TOTAL 15 664.56 0
Bentley Sukraj 1 0 0
Bentley Terry 4 0 0
Bentley TOTAL 5 0 0
Jaguar Emma 10 2448 1224
Jaguar Paul 1 0 0
Jaguar Simon 7 2754 918
Jaguar TOTAL 18 5202 2142
GROUP TOTAL 2611 96591.62 42130.14
The ROLLUP places a null in the totals row so if you want to replace that I would suggest taking your existing query and placing it in a subquery and then use a CASE on the NAME to replace the null to Total .
The ISNULL Function is a built-in function to replace nulls with specified replacement values. To use this function, all you need to do is pass the column name in the first parameter and in the second parameter pass the value with which you want to replace the null value.
The SUM function returns the sum of the input column or expression values. The SUM function works with numeric values and ignores NULL values.
All rows with a NULL in the column are treated as if NULL was another value. If a grouping column contains null values, all null values are considered equal, and they are put into a single group. Show activity on this post. Group By groups all the records with NULL values.
To resolve the issue with COALESCE/IFNULL
still returning NULL
for the WITH ROLLUP
placeholders, you need to GROUP BY
the table column names, rather than the aliased column expressions.
The issue is caused by the GROUP BY
clause being specified on the aliased column expressions, because the aliases are assigned after the column expression is processed.
Resulting in the WITH ROLLUP
NULL
placeholders not being in the recordset to be evaluated by COALESCE
.
Meaning the aliases DEALER
, SERVICE_ADVISOR
in the GROUP BY
do not exist until after IFNULL/COALESCE
have already been executed.
See MySQL Handling of GROUP BY
for more details.
Example DB-Fiddle
CREATE TABLE foo (
`amount` INTEGER,
`created` INTEGER
);
INSERT INTO foo
(`amount`, `created`)
VALUES
('1', '2019'),
('2', '2019');
Query #1 (Reproduce Issue)
SELECT
SUM(amount) AS amounts,
COALESCE(created, 'Total') AS created_coalesce
FROM foo
GROUP BY created_coalesce WITH ROLLUP;
| amounts | created_coalesce |
| ------- | ---------------- |
| 3 | 2019 |
| 3 | |
Query #2 (Corrected)
SELECT
SUM(amount) AS amounts,
COALESCE(created, 'Total') AS created_coalesce
FROM foo
GROUP BY foo.created WITH ROLLUP;
| amounts | created_coalesce |
| ------- | ---------------- |
| 3 | 2019 |
| 3 | Total |
Example DB-Fiddle
SELECT
COALESCE(usergroups.name, 'GROUP') AS DEALER,
COALESCE(users.name, 'TOTAL') AS SERVICE_ADVISOR,
COUNT(DISTINCT vcrs.uid) AS COMPLETED,
/* ... */
GROUP BY usergroups.name, users.name WITH ROLLUP;
Query #1 (Original)
SELECT
COALESCE(usergroups.name, 'GROUP') AS DEALER,
COALESCE(users.name, 'TOTAL') AS SERVICE_ADVISOR,
COUNT(DISTINCT vcrs.uid) AS COMPLETED
/* ... */
GROUP BY DEALER, SERVICE_ADVISOR WITH ROLLUP;
| DEALER | SERVICE_ADVISOR | COMPLETED |
| ------ | --------------- | --------- |
| Foo | Jane Doe | 1 |
| Foo | John Doe | 1 |
| Foo | | 2 |
| | | 2 |
Query #2 (Corrected)
SELECT
COALESCE(usergroups.name, 'GROUP') AS DEALER,
COALESCE(users.name, 'TOTAL') AS SERVICE_ADVISOR,
COUNT(DISTINCT vcrs.uid) AS COMPLETED
/* ... */
GROUP BY usergroups.name, users.name WITH ROLLUP;
| DEALER | SERVICE_ADVISOR | COMPLETED |
| ------ | --------------- | --------- |
| Foo | Jane Doe | 1 |
| Foo | John Doe | 1 |
| Foo | TOTAL | 2 |
| GROUP | TOTAL | 2 |
With MySQL 5.7+ and ONLY_FULL_GROUP_BY enabled, selected non-aggregate columns that are not specified in the
GROUP BY
clause will fail. Meaning the following query will not work as expected: DB-FiddleSELECT COALESCE(YEAR(foo), 'foo') /* ... */ GROUP BY YEAR(foo) WITH ROLLUP -> ER_WRONG_FIELD_WITH_GROUP: Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.foo_bar.foo' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
COALESCE
,IFNULL
,IF(... IS NULL)
andCASE WHEN ... IS NULL
will all function similarly. WhereIFNULL
is the proprietary to MySQL and is a less functional replacement ofCOALESCE
. AsCOALESCE
can accept more than two parameters to check againstNULL
, returning the firstnon-NULL
value.mysql> SELECT COALESCE(NULL, NULL, 1, NULL); -> 1 mysql> SELECT IFNULL(NULL, 1); -> 1 mysql> SELECT IF(NULL IS NULL, 1, ''); -> 1 mysql> SELECT CASE WHEN NULL IS NULL THEN 1 END; -> 1
nullable columns in the
GROUP BY
as either aliases or column names, will result in theNULL
values being displayed as theWITH ROLLUP
placeholder. This applies to usingWITH ROLLUP
in general. For example ifusers.name
can returnNULL
. DB-Fiddle| DEALER | SERVICE_ADVISOR | COMPLETED | | ------ | --------------- | --------- | | Foo | TOTAL | 1 | | Foo | Jane Doe | 1 | | Foo | John Doe | 1 | | Foo | TOTAL | 3 | | GROUP | TOTAL | 3 |
NULL
column values from being displayedTo ensure that nullable columns are not accidentally included, you would need to specify in the criteria to exclude them.
Example DB-Fiddle
SELECT
COALESCE(usergroups.name, 'GROUP') AS DEALER,
COALESCE(users.name, 'TOTAL') AS SERVICE_ADVISOR,
COUNT(DISTINCT vcrs.uid) AS COMPLETED
FROM vcrs
LEFT JOIN users
ON users.id = vcrs.uid
LEFT JOIN usergroups
ON usergroups.id = users.group_id
WHERE vcrs.vcrSubStatus = 4
AND users.name IS NOT NULL
GROUP BY usergroups.name, users.name
WITH ROLLUP;
Result
| DEALER | SERVICE_ADVISOR | COMPLETED |
| ------ | --------------- | --------- |
| Foo | Jane Doe | 1 |
| Foo | John Doe | 1 |
| Foo | TOTAL | 2 |
| GROUP | TOTAL | 2 |
Since
LEFT JOIN
is used on thevcrs
table,IS NOT NULL
must be applied to theWHERE
clause, instead of theON
clause. AsLEFT JOIN
returnsNULL
for non-matching criteria. To circumvent the issue, use anINNER JOIN
to limit the resultset to only those with matchingON
criteria.
/* ... */
INNER JOIN users
ON users.id = vcrs.uid
AND users.name IS NOT NULL
/* ... */
WHERE vcrs.vcrSubStatus = 4
GROUP BY usergroups.name, users.name
WITH ROLLUP;
NULL
columns valuesTo explicitly include nullable column values, without duplicating the WITH ROLLUP
placeholder name, you would need to utilize a derived table subquery to substitute the NULL
value as a textual value.
Example DB-Fiddle
SELECT
COALESCE(v.usergroup_name, 'GROUP') AS DEALER,
COALESCE(v.user_name, 'TOTAL') AS SERVICE_ADVISOR,
COUNT(DISTINCT v.uid) AS COMPLETED
FROM (
SELECT
usergroups.name AS usergroup_name,
COALESCE(users.name, 'NULL') AS user_name,
vcrs.uid
FROM vcrs
LEFT JOIN users
ON users.id = vcrs.uid
LEFT JOIN usergroups
ON usergroups.id = users.group_id
WHERE vcrs.vcrSubStatus = 4
) AS v
GROUP BY v.usergroup_name, v.user_name
WITH ROLLUP;
Result
| DEALER | SERVICE_ADVISOR | COMPLETED |
| ------ | --------------- | --------- |
| Foo | Jane Doe | 1 |
| Foo | John Doe | 1 |
| Foo | NULL | 1 |
| Foo | TOTAL | 3 |
| GROUP | TOTAL | 3 |
You can also optionally replace the 'NULL'
textual placeholder as desired and even display it as NULL
.
SELECT
COALESCE(v.usergroup_name, 'GROUP') AS DEALER,
CASE v.user_name WHEN 'NULL' THEN NULL ELSE COALESCE(v.user_name, 'TOTAL') END AS SERVICE_ADVISOR,
COUNT(DISTINCT v.uid) AS COMPLETED
FROM (
/* ... */
) AS v
GROUP BY v.usergroup_name, v.user_name
WITH ROLLUP;
I'm only 2 years too late, but since I came across the same issue as @the_gimlet I thought I'd post the answer.
So don't know if this is a mySQL versioning or something, but using mysql 5.6 I get the same problem... ifnull will not replace the rollup 'nulls'.
Simply get around this by making your rollup a subquery, and doing the ifnulls in the main select... annoying to repeat the select, but it works!
e.g. for example above
SELECT
IFNULL(`DEALER`, 'GROUP') AS DEALER,
IFNULL(`SERVICE_ADVISOR`, 'TOTAL') AS SERVICE_ADVISOR,
`COMPLETED`,
/* .......... */
FROM (SELECT
usergroups.name AS DEALER,
users.name AS SERVICE_ADVISOR,
COUNT(DISTINCT vcrs.uid) AS COMPLETED,
/* .......... */
AND vcrs.vcrSubStatus = 4
GROUP BY DEALER, SERVICE_ADVISOR with ROLLUP);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With