【问题标题】:Grouping and summing two SQL tables, and replacing missing values对两个 SQL 表进行分组和求和,并替换缺失值
【发布时间】:2020-03-27 19:42:32
【问题描述】:

我有下表“人员”:

|    id   |  name   | 
| ------  |  -----  |
|    1    |  Adam   |  
|    2    |  Nick   |
|    3    |  John   |

另一个表“金额”:

id  amount  month  customerid
 1   500    Jan      1
 2   1000   Feb      1
 3   1200   Jan      1
 4   700    Jan      2
 5   400    Feb      2
 6   210    Jan      null
 7   230    Feb      null

persons.id 对应于 amount.customerid

如何返回一个 sql 查询,该查询返回一月份每人产生的金额,其中 null customerid 的名称为“未知”?

|   name  |  value  | 
| ------  |  -----  |
|   Adam  |  1700   |  
|   Nick  |  700    |
|   John  |  0      |
| Unknown |  210    |

【问题讨论】:

  • 名称和值是糟糕的表名。Persons(或者可能是客户)是更好的表名。此外, value 是一个糟糕的列名。什么价值?
  • 做一个外连接。分组。
  • 编辑了表名。
  • @jarlh 我正在尝试在不支持外连接的 sqlite 上使用此示例。还有其他方法可以解决这个问题吗?
  • 您应该提及/标记您使用的 SQL 方言。如果是 Oracle,这里有一个指针:oracle-base.com/articles/misc/null-related-functions

标签: sql sqlite join group-by


【解决方案1】:

我相信 LEFT JOIN 和 COALESCE() 会在这里解决问题:

SELECT COAELSCE(persons.name, 'Unknown') as personname, sum(amount) sumamount
FROM  amounts
    LEFT OUTER JOIN person ON amounts.customerid = persons.id
GROUP BY COALESCE(persons.name, 'Unknown')
WHERE month = 'Jan';

【讨论】:

    【解决方案2】:

    如果不使用 LEFT JOIN,您可以分两步完成。首先为已知人员加入并聚合。然后添加未知数。

    select p.name, sum(a.amount)
    from amounts a
    join persons p on a.customerid = p.id
    where a.month = 'Jan'
    group by p.name
    
    union all
    
    select 'Unknown', sum(amount)
    from amounts
    where a.month = 'Jan' and customerid is null
    

    【讨论】:

      【解决方案3】:

      从技术上讲,您想要的是表之间的完全连接。遗憾的是,SQLite 不支持FULL JOIN

      有多种方法可以模拟解决方案。不过,对于这种特殊情况,我认为使用LEFT JOIN 来获取所有人员就足够了。然后UNION ALL 引入未知数:

      select p.name, coalesce(sum(a.value), 0) value 
      from persons p left join
           amounts a
           on a.customerid = p.id and
              a.month = 'Jan'
      group by p.name
      union all
      select 'Unknown', sum(a.value)
      from amounts a
      where a.customerid is null;
      

      Here 是一个 dbfiddle。

      第一个查询使用left join 引入所有客户,即使是没有金额的客户。第二个引入了“未知”。

      【讨论】:

        【解决方案4】:

        您的要求可以通过FULL OUTER JOIN 解决,但 SQLite 不支持它。
        因此,您可以将UNION ALL 用于表persons 以包含具有null id 和LEFT JOIN 的行:

        select p.name, coalesce(sum(a.value), 0) value 
        from (select * from persons union all select null, 'Unknown') p 
        left join (select * from amounts where month = 'Jan') a
        on (p.id = a.customerid) or (p.id is null and a.customerid is null)
        where p.id is not null or a.value is not null
        group by p.id, p.name
        order by p.name is null, p.name
        

        条件:

        where p.id is not null or a.value is not null
        

        确保如果没有customerids 和null,那么在结果中将没有名称为'Unknown'value = 0 的行。
        请参阅demo
        结果:

        | name    | value |
        | ------- | ----- |
        | Adam    | 1700  |
        | Nick    | 700   |
        | John    | 0     |
        | Unknown | 210   |
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-11-01
          • 2014-10-21
          • 1970-01-01
          • 2023-04-02
          • 2021-05-19
          • 2011-05-26
          • 1970-01-01
          相关资源
          最近更新 更多