LEFT JOIN多个表的问题

时间:2017-08-31 23:53:44

标签: postgresql join left-join

我有以下查询

SELECT a.account_id, sum(p.amount) AS amount
FROM accounts a
LEFT JOIN users_accounts ua
    JOIN users u
        JOIN payments p on p.meta_id = u.user_id
    ON u.user_id = ua.user_id
ON ua.account_id = a.account_id
WHERE p.date_prcsd BETWEEN '2017-08-01 00:00:00' AND '2017-08-31 23:59:59'
GROUP BY a.account_id
ORDER BY account_id ASC;

我想要的是accounts a中的所有行和缺少金额数据的零。不同类型的连接和不同的连接结构的结果集相同 - 只有在p。

中有一些付款的行

我哪里出错了?

1 个答案:

答案 0 :(得分:1)

简化为:

SELECT a.account_id
,sum(coalesce(p2.amount, 0)) AS amount
FROM accounts a
LEFT JOIN users_accounts ua ON (a.account_id = ua.account_id)
LEFT JOIN users u ON (ua.user_id = u.user_id)
LEFT JOIN (
    SELECT p.meta_id
    ,p.amount
    FROM payments p
    WHERE p.date BETWEEN '2017-08-01' AND '2017-08-10'
) AS p2 ON (u.user_id = p2.meta_id)
GROUP BY a.account_id
ORDER BY account_id ASC;

结果:

  account_id | amount
 ------------+--------
           1 |      4
           2 |      0
           3 |      0
 (3 rows)

说明:您需要处理所有返回的空值。 coalesce()为你做到了。 where子句实际上是解决方案中的真正问题,因为它会过滤掉您希望在endresult中拥有的行。最重要的是:你遗漏了其他表的左连接。我创建了一个简化的测试数据库:

$ cat tables.sql
drop table users_accounts;
drop table payments;
drop table users;
drop table accounts;

create table accounts (account_id serial primary key, name varchar not 
null);
create table users (user_id serial primary key, name varchar not null);
create table users_accounts(user_id int references users(user_id),
                            account_id int references 
                            accounts(account_id));
create table payments(meta_id int references users(user_id), amount int 
not null, date date);

insert into accounts (account_id, name) values (1, 'Account A'), (2, 
'Account B'), (3, 'Account C');
insert into users (user_id, name) values (1, 'Marc'), (2, 'Ruben'), (3, 
'Isaak');
insert into users_accounts (user_id, account_id) values (1,1),(2,1);
insert into payments(meta_id, amount, date) values (1,1, '2017-08-01'),
(1,2, '2017-08-11'),(1,3, '2017-08-03'),(2,1, null),(2,2, null),(2,3, 
null);