MySQL 按空值和非空值分组
Posted
技术标签:
【中文标题】MySQL 按空值和非空值分组【英文标题】:MySQL group by null and not null values 【发布时间】:2021-09-03 12:09:43 【问题描述】:我有一张这样的桌子:
id | cluster_id | user_id | name | ...
1 | 1 | 1 | test name
2 | 1 | 3 | other
3 | null | 1 | one more
4 | 2 | 1 | foo
5 | null | 1 | bar
6 | 1 | 1 | baz
我想创建一个按cluster_id
列分组的查询,但只按具有非空值的列分组,这样我就得到了这样的结果:
id | cluster_id | user_id | ...
1 | 1 | 1 | test name
3 | null | 1 | one more
4 | 2 | 1 | foo
5 | null | 1 | bar
我想要一个具有不同 cluster_id 的列表,但仅限于 cluster_id 不为空的地方。我还想过滤任意列,例如user_id
。
在上述结果中,我还查询了user_id
,其中user_id
为1。
如何创建这样的查询?
提前致谢!
【问题讨论】:
这看起来一样,你可以创建一个minimal reproducible example 以便我们了解你想要达到的目标 @nbk 我已经更新了问题。我希望现在应该更清楚了:) 嗯,the columns that have a not null value
并且您的示例目标表中有一个空值 - 不太确定您要在那里实现什么。
@LukeBriggs 已修复
【参考方案1】:
查询很简单。
GROUP BY 也适用于 NULL 值
我做了两个查询,第一个包含 user_id 最后一个不包含
你必须用id作为主键来测试这个,看看排除NULL是否会带来一些性能
CREATE TABLE tab1 ( `id` INTEGER, `cluster_id` int, `user_id` INTEGER, `name` VARCHAR(20) );
INSERT INTO tab1 (`id`, `cluster_id`, `user_id`, `name`) VALUES ('1', '1', '1', 'test name'), ('2', '1', '3', 'other'), ('3', null, '1', 'one more'), ('4', '2', '1', 'foo'), ('5', null, '1', 'bar'), ('6', '1', '1', 'baz');
编号 | cluster_id |用户 ID |姓名 -: | ---------: | ------: | :-------- 1 | 1 | 1 |测试名称 2 | 1 | 3 |其他 3 | 空 | 1 |多一个 4 | 2 | 1 |富 5 | 空 | 1 |酒吧SELECT * FROM tab1 WHERE `id` IN (SELECT MIN(`id`) FROM tab1 GROUP BY `cluster_id`,`user_id`) UNION SELECT * FROM tab1 WHERE `cluster_id` IS NULL
编号 | cluster_id |用户 ID |姓名 -: | ---------: | ------: | :-------- 1 | 1 | 1 |测试名称 2 | 1 | 3 |其他 4 | 2 | 1 |富 3 | 空 | 1 |多一个 5 | 空 | 1 |酒吧SELECT * FROM tab1 WHERE `id` IN (SELECT MIN(`id`) FROM tab1 WHERE `cluster_id` IS NOT NULL GROUP BY `cluster_id`,`user_id`) UNION SELECT * FROM tab1 WHERE `cluster_id` IS NULL
编号 | cluster_id |用户 ID |姓名 -: | ---------: | ------: | :-------- 1 | 1 | 1 |测试名称 3 | 空 | 1 |多一个 4 | 2 | 1 |富 5 | 空 | 1 |酒吧SELECT * FROM tab1 WHERE `id` IN (SELECT MIN(`id`) FROM tab1 GROUP BY `cluster_id`) UNION SELECT * FROM tab1 WHERE `cluster_id` IS NULL
编号 | cluster_id |用户 ID |姓名 -: | ---------: | ------: | :-------- 1 | 1 | 1 |测试名称 4 | 2 | 1 |富 3 | 空 | 1 |多一个 5 | 空 | 1 |酒吧SELECT * FROM tab1 WHERE `id` IN (SELECT MIN(`id`) FROM tab1 WHERE `cluster_id` IS NOT NULL GROUP BY `cluster_id`) UNION SELECT * FROM tab1 WHERE `cluster_id` IS NULL
db小提琴here
【讨论】:
当cluster_id
为null
时,不应将其分组,仅对具有非空值的记录进行分组。在这种情况下,这将导致 2 个空记录。
我错过了那部分。 mi改了我的答案,你必须测试哪个更快
感谢您的回答。我遇到的问题是,每当我想过滤掉特定用户的结果时,查询总是会返回带有 cluster_id 的记录结果。如果我在 user_id=3
上查询,查询总是返回记录,即使不存在具有该 ID 的记录。
就是基本的sql add AND user_id = 3
after cluster_id IS NULL
AND cluster_id IS NOT NULL
你要明白union是结合了两个独立的查询结构相同的,所以你过滤了之前的UNION或者之后以上是关于MySQL 按空值和非空值分组的主要内容,如果未能解决你的问题,请参考以下文章