【问题标题】:LEFT JOIN trouble with multiple tables多个表的 LEFT JOIN 问题
【发布时间】:2017-08-31 23:53:44
【问题描述】:

我有以下问题

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 中有一些付款的行。

我哪里出错了?

【问题讨论】:

    标签: postgresql join left-join


    【解决方案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 子句实际上是您的解决方案中的真正问题,因为它过滤掉了您希望在最终结果中包含的行。最重要的是:您省略了其他表的左连接。我创建了一个简化的测试数据库:

    $ 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);
    

    【讨论】:

    • 这个查询确实有效,但是一旦我应用WHERE 子句,它只返回在给定时间段内在payments 中有记录的几行。在发布问题之前我已经尝试过COALESCE,但没有成功
    • 现在我们开始谈了 :) Mucho 谢谢,就像一个魅力!
    猜你喜欢
    • 1970-01-01
    • 2019-08-12
    • 1970-01-01
    • 2012-06-21
    • 2012-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-02
    相关资源
    最近更新 更多