MySQL 按空值和非空值分组

MySQL group by null and not null values

我有一个 table 这样的:

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_ids 的列表,但仅在 cluster_id 不为空的情况下。另外我想过滤任意列,如 user_id.

在上面的结果中,我还查询了 user_id,其中 user_id 是 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');
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
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      
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
id | cluster_id | user_id | name     
-: | ---------: | ------: | :--------
 1 |          1 |       1 | test name
 2 |          1 |       3 | other    
 4 |          2 |       1 | foo      
 3 |       null |       1 | one more 
 5 |       null |       1 | bar      
SELECT * FROM  tab1 WHERE `id` IN (SELECT MIN(`id`) FROM tab1 GROUP BY `cluster_id`)
UNION 
SELECT * FROM tab1 WHERE `cluster_id` IS NULL
id | cluster_id | user_id | name     
-: | ---------: | ------: | :--------
 1 |          1 |       1 | test name
 3 |       null |       1 | one more 
 4 |          2 |       1 | foo      
 5 |       null |       1 | bar      
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
id | cluster_id | user_id | name     
-: | ---------: | ------: | :--------
 1 |          1 |       1 | test name
 4 |          2 |       1 | foo      
 3 |       null |       1 | one more 
 5 |       null |       1 | bar      

db<>fiddle here