【问题标题】:Summarize Null Values in Table with Group By使用 Group By 汇总表中的 Null 值
【发布时间】:2019-08-21 13:33:36
【问题描述】:

我有两张桌子:

  • 人员(ID、姓名)
  • 运动(person_ID,运动)

问题:Sport 可以有 NULL 值。如果是这种情况,那么如果我按 ID 分组,那么这项运动应该是 NULL。

SELECT p.ID, p.Name, s.Sport
FROM Person p
INNER JOIN Sports s ON p.ID=s.person_id
GROUP BY p.ID

如果没有 Group By 表如下所示:

p.ID p.Name s.Sport
1    tom    soccer
1    tom    NULL
2    lisa   golf
2    lisa   soccer
3    tim    golf
3    tim    NULL

我现在想要什么:

1 tom NULL
2 lisa golf
3 tim NULL

但我得到了什么:

1 tom soccer
2 lisa golf
3 tim golf

我已经尝试过 subselects 和 ifs 但我什么都做不了。提前致谢!

【问题讨论】:

  • 为什么丽莎应该打高尔夫球而不是足球?
  • 如果我运行这个,如果有多个(在我的系统上),Group by 函数总是选择第一行。但这并不重要。我只需要 tim 和 tom 为 NULL
  • 在选择列表中使用case表达式进行条件聚合。如果列有空值,请记住 count(*) count(column)。
  • @stuckonhere 为什么不将where sport is NULL 添加到查询中?
  • 如果我只添加 IS NULL 它会删除 lisa 条目,我需要这个条目。

标签: sql sqlite group-by


【解决方案1】:

这是一个应该生成您预期的结果集的查询,尽管正如 @jarlh 所指出的,目前尚不清楚为什么 Lisa 应该打高尔夫球而不是足球。

SELECT
    p.ID,
    p.Name,
    CASE WHEN COUNT(CASE WHEN s.Sport IS NULL THEN 1 END) > 0
         THEN NULL ELSE MIN(s.Sport) END AS Sport
FROM Person p
INNER JOIN Sports s
    ON p.ID = s.person_id
GROUP BY
    p.ID,
    p.name;

请注意,我按 IDname 进行分组,这在许多数据库(尽管可能不是 SQLite)上都是必需的。

【讨论】:

  • 这行得通!这是非常有用的表达式 Count(Case...)。非常感谢。
【解决方案2】:

您不能使用聚合函数作为 MIN() 来管理 NULL 值 但你可以试试

SELECT p.ID, p.Name, min(ifnull(s.Sport,'')) 
FROM Person p 
INNER JOIN Sports s ON p.ID=s.person_id 
GROUP BY p.ID, p.name

【讨论】:

    【解决方案3】:

    假设你使用的SQLLite版本支持row_number(),请在下面试一下,如果你order by s.sport ASC,可以将row_number设置为1,然后选择每个类别的第一行。如果有NULL,它应该通过这个查询定位到每个类别的第一行。你不需要使用group by

    ;with cte as (
    select p.ID, p.Name, s.Sport, 
           ROW_NUMBER() OVER (PARTITION BY p.ID ORDER BY s.Sport ASC) AS rn
    FROM Person p INNER JOIN Sports s ON p.ID=s.person_id
    )
    select *
    from cte
    where rn=1
    

    【讨论】:

    • 这当然假设OP的SQLite版本支持ROW_NUMBER
    【解决方案4】:

    您可以使用相关子查询来执行此操作,避免外部查询中的 join

    select p.*,
           (select s.sport
            from sports s
            where s.personId = p.id
            order by (s.sport is null) desc, s.sport asc
           ) as min_sport
    from person p;
    

    这在某些情况下可能很有用。使用sports(personid, sport) 上的索引,它可能group by 快​​,具体取决于数据(很多人,每人很少运动)。

    此外,这与您的查询略有不同,因为它返回所有人,即使是没有运动的人。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-26
      • 2018-04-30
      • 2010-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多