显示给定用户的交易余额

时间:2017-05-07 17:34:22

标签: mysql with-statement full-outer-join

我需要为每个用户显示余额,与其他用户相关

表结构&虚拟数据脚本:

CREATE TABLE transactions (
    id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    user1 INT NOT NULL,
    user2 INT NOT NULL,
    amount INT NOT NULL
);
INSERT INTO transactions VALUES(1, 1, 2, 10);
INSERT INTO transactions VALUES(2, 1, 3, 15);
INSERT INTO transactions VALUES(3, 4, 1, 25);
INSERT INTO transactions VALUES(4, 1, 5, 20);
INSERT INTO transactions VALUES(5, 5, 1, 18);
INSERT INTO transactions VALUES(6, 5, 1, 2);

结果:

enter image description here

现在我想总结一下user = 1的信息(余额)。我希望看到的结果是:

user    balance
2   10
3   15
4   -25
5   0

现在,我正在使用最新的稳定MySQL版本5.7.17-0ubuntu0.16.04.1。 我有两个问题:

  • MySQL不支持FULL OUTER JOIN子句
  • MySQL不支持WITH子句

此时我的双手被束缚住了。有人可以通过fastefficient查询上述情况来帮助我吗?

以下是我的两次尝试(无效):

这个没有用,因为我不能使用FULL OUTER JOIN子句

SELECT IFNULL(t3.user, t4.user), IFNULL(t3.amount, 0) - IFNULL(t4.amount, 0)
FROM (
    select t1.user2 user, sum(t1.amount) amount
    from transactions t1
    where 1=1
        and t1.user1 = 1
    group by t1.user2
) t3
FULL OUTER JOIN (
    select t2.user1 user, sum(t2.amount) amount
    from transactions t2
    where 1=1
        and t2.user2 = 1
    group by t2.user1
) t4 ON t3.user = t4.user

这个没有用,因为我不能使用WITH子句

WITH t3 AS
 (
    select t1.user2 user, sum(t1.amount) amount
    from transactions t1
    where 1=1
        and t1.user1 = 1
    group by t1.user2
),
t4 AS
(
    select t2.user1 user, sum(t2.amount) amount
    from transactions t2
    where 1=1
        and t2.user2 = 1
    group by t2.user1
)
SELECT
    t1.user,
    IFNULL(t3.amount, 0) - IFNULL(t4.amount, 0) balance
FROM t1
LEFT JOIN t3 ON t1.user = t2.user
UNION
SELECT t2.user FROM t1
RIGHT JOIN t3 ON t1.user = t2.user

更新

使用 Gurwinder Singh 提供的解决方案,我能够测试大约5百万行测试数据的两个查询的性能(尽管user1 = 1或user2 = 1的数据数量) - 远不止于此。)

enter image description here

和(与工会)

enter image description here

相应。查询1 快34%((3.4-2.24)/3.4*100 = 34)。

请注意,此表中没有索引。我稍后会尝试使用MariaDB进行相同类型的测试并比较结果。

更新2

为列编制索引后:user1user2amount情况已发生变化。

查询1运行时间:

显示0到2行(总共3行,查询耗时1.9857秒。)

查询2运行时间:

显示0到2行(总共3行,查询耗时1.5641秒。)

但我仍然认为这是非常糟糕的结果。也许我会设置一些触发器来将余额更新为专用表。但在这一点上,答案得到了回答。

1 个答案:

答案 0 :(得分:1)

您可以使用基于CASE的条件聚合:

试试这个:

select case 
        when user1 = 1
            then user2
        else user1
        end as user,
    sum(case 
            when user1 = 1
                then amount
            else - amount
            end) as amount
from transactions
where 1 in (user1, user2)
group by case 
        when user1 = 1
            then user2
        else user1
        end;

Demo

或两步聚合:

select user, sum(amount) as amount
from (
    select user2 as user, sum(amount) as amount
    from transactions
    where user1 = 1
    group by user2

    union all

    select user1 as user, -sum(amount) as amount
    from transactions
    where user2 = 1
    group by user1
) t
group by user;

Demo

相关问题