要解决COALESCE/IFNULL
仍然返回NULL
占位符的问题WITH ROLLUP
,您需要GROUP BY
表列名称,而不是别名列表达式。
该问题是由在GROUP BY
别名列表达式上指定的子句引起的,因为别名是在处理列表达式之后分配的。
导致WITH ROLLUP
NULL
占位符不在要由 评估的记录集中COALESCE
。
意思是别名DEALER
,SERVICE_ADVISOR
在已经执行之前GROUP BY
不存在。有关更多详细信息,请参阅 MySQL处理。 IFNULL/COALESCE
GROUP BY
示例 DB-Fiddle
CREATE TABLE foo (
`amount` INTEGER,
`created` INTEGER
);
INSERT INTO foo
(`amount`, `created`)
VALUES
('1', '2019'),
('2', '2019');
查询 #1(重现问题)
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 | |
查询 #2(已更正)
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 |
特定用例
示例 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;
查询 #1(原始)
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 |
查询 #2(已更正)
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 |
注意事项
-
启用MySQL 5.7+ 和ONLY_FULL_GROUP_BY后,未在子句中指定的选定非聚合列GROUP BY
将失败。意味着以下查询将无法按预期工作:DB-Fiddle
SELECT 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)
和CASE WHEN ... IS NULL
都将具有类似的功能。哪里IFNULL
是 MySQL 专有的,是COALESCE
. AsCOALESCE
可以接受两个以上的参数进行检查NULL
,返回第一个non-NULL
值。
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
-
中的可空列GROUP BY
作为别名或列名,将导致NULL
值显示为WITH ROLLUP
占位符。这适用WITH ROLLUP
于一般使用。例如 if
users.name
可以返回NULL
. DB-小提琴
| DEALER | SERVICE_ADVISOR | COMPLETED |
| ------ | --------------- | --------- |
| Foo | TOTAL | 1 |
| Foo | Jane Doe | 1 |
| Foo | John Doe | 1 |
| Foo | TOTAL | 3 |
| GROUP | TOTAL | 3 |
防止NULL
显示列值
为确保不会意外包含可为空的列,您需要在条件中指定以排除它们。
示例 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;
结果
| DEALER | SERVICE_ADVISOR | COMPLETED |
| ------ | --------------- | --------- |
| Foo | Jane Doe | 1 |
| Foo | John Doe | 1 |
| Foo | TOTAL | 2 |
| GROUP | TOTAL | 2 |
由于LEFT JOIN
是在vcrs
表上使用,IS NOT NULL
必须应用于WHERE
子句,而不是ON
子句。作为不匹配标准的LEFT JOIN
回报NULL
。要规避此问题,请使用 anINNER JOIN
将结果集限制为仅具有匹配ON
条件的结果集。
/* ... */
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
列值
要显式包含可为空的列值,而不复制WITH ROLLUP
占位符名称,您需要利用派生表子查询将该NULL
值替换为文本值。
示例 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;
结果
| DEALER | SERVICE_ADVISOR | COMPLETED |
| ------ | --------------- | --------- |
| Foo | Jane Doe | 1 |
| Foo | John Doe | 1 |
| Foo | NULL | 1 |
| Foo | TOTAL | 3 |
| GROUP | TOTAL | 3 |
您还可以'NULL'
根据需要选择替换文本占位符,甚至将其显示为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;