【问题标题】:PostgreSQL SUM doesnt return values with 0 rowsPostgreSQL SUM 不返回 0 行的值
【发布时间】:2018-11-19 12:13:37
【问题描述】:

我有一个交易表,每笔交易都有一个地址字段引用地址表中的一行,地址表中的每个地址都有一个 coinID。

我想获取特定用户每枚硬币的所有交易的总和。

我遇到的问题是,如果用户有 0 笔交易或属于特定硬币的地址,则结果将完全丢失。我需要硬币表中包含 0 个交易或地址的所有硬币返回总和为 0。

SELECT coins.name, SUM(transactions.amount),coins.price_usd
            FROM coins
            LEFT JOIN addresses ON addresses.coin_id = coins.id
            LEFT JOIN transactions ON transactions.address = addresses.address
            LEFT JOIN users ON transactions.user_id = users.id
            WHERE users.email = 'testemail@email.com'
            GROUP BY coins.name, coins.price_usd

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:

    这个解决方案告诉你你想要什么:

    create table coins (
      id int,
      name varchar(10),
      price_usd int
    );
    
    insert into coins (id, name, price_usd) values (1, 'Pound', 2);
    insert into coins (id, name, price_usd) values (2, 'Yen', 98);
    insert into coins (id, name, price_usd) values (3, 'Euro', 3);
    
    create table addresses (
      coin_id int,
      address int
    );
    
    insert into addresses (coin_id, address) values (1, 20);
    insert into addresses (coin_id, address) values (3, 30);
    
    create table transactions (
      address int,
      user_id int,
      amount int
    );
    
    insert into transactions (address, user_id, amount) values (20, 500, 123);
    insert into transactions (address, user_id, amount) values (20, 500, 101);
    insert into transactions (address, user_id, amount) values (30, 501, 456);
    
    create table users (
      id int,
      email varchar(50)
    );
    
    insert into users (id, email) values (500, 'testemail@email.com');
    insert into users (id, email) values (501, 'another@email.com');
    
    select coins.name, sum(transactions.amount),coins.price_usd
      from coins
      join addresses on addresses.coin_id = coins.id
      join transactions on transactions.address = addresses.address
      join users on transactions.user_id = users.id
      where users.email = 'testemail@email.com'
      group by coins.name, coins.price_usd
    union all
    select name, 0, 0
      from coins
      where id not in (
        select coin_id 
          from addresses
          join transactions on transactions.address = addresses.address
          join users on transactions.user_id = users.id
          where users.email = 'testemail@email.com'
      );
    

    结果:

    name   sum  price_usd
    -----  ---  ---------
    Pound  224          2  -- the requested user
    Yen      0          0  -- another user
    Euro     0          0  -- coin with no transactions
    

    【讨论】:

    • 谢谢。不是完全必要的,但是在没有行的情况下,有一种简单的方法可以让值等于 0 而不是 null
    • 可以使用COALESCE函数,如:COALESCE(my_value, 0):如果my_value为null,则返回第二个参数(0)。
    • 此解决方案实际上不起作用。它将为硬币表中的所有硬币生成一行,但是 sum(transactions.amount) 将反映该硬币每笔交易的总和(不仅仅是 users.email 为 testemail@email.com 的那些)。
    • 我还在查询顶部使用交叉连接实现了一个解决方案。好奇您是否看到使用 Union 而不是 Cross Join 的解决方案有什么好处
    • 交叉连接将从两个表中读取所有行。另一方面,联合将运行两次,首先读取行的一个子集(可能是 50%?),然后读取行的另一个小子集(可能是 10%?)。我猜工会可能会更快;但是,我认为差异可以忽略不计。我不会太在意它,除非你有数百万行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-15
    • 1970-01-01
    • 1970-01-01
    • 2018-01-09
    • 2010-10-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多