显示给定用户的交易余额
Showing balances of transactions for a given user
我有一种情况需要显示每个用户的余额,相对于其他用户。
Table 结构和虚拟数据脚本:
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);
结果:
现在我想汇总用户 = 1
的信息(余额)。我想看到的结果是这样的:
user balance
2 10
3 15
4 -25
5 0
现在,我使用的是最新的 stable MySQL 版本 5.7.17-0ubuntu0.16.04.1
。
我有 2 个问题:
- MySQL不支持
FULL OUTER JOIN
子句
- MySQL不支持
WITH
子句
此时我束手无策。我想为上述情况编写一个快速高效的查询。这是我的两次尝试(none 有效):
这个不起作用,因为我不能使用 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 提供的解决方案,我能够在大约 500 万行测试数据上测试这两个查询的性能(尽管 user1 = 1 或 user2 = 1 - 远小于此)。
和(联合)
因此。查询 1 快 34% ((3.4-2.24)/3.4*100 = 34).
请注意,此 table 上没有索引。稍后我将尝试使用 MariaDB 进行相同类型的测试并比较结果。
更新 2
索引列后:user1
、user2
、amount
情况发生了变化。
查询 1 运行 时间:
显示第 0 - 2 行(共 3 行,查询耗时 1.9857 秒。)
查询2运行时间:
显示第 0 - 2 行(共 3 行,查询耗时 1.5641 秒。)
但我仍然认为这是一个很糟糕的结果。也许我会把一些触发器更新到专用的 table 中。不过至此答案有了答案。
您可以使用基于 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
我有一种情况需要显示每个用户的余额,相对于其他用户。
Table 结构和虚拟数据脚本:
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);
结果:
现在我想汇总用户 = 1
的信息(余额)。我想看到的结果是这样的:
user balance
2 10
3 15
4 -25
5 0
现在,我使用的是最新的 stable MySQL 版本 5.7.17-0ubuntu0.16.04.1
。
我有 2 个问题:
- MySQL不支持
FULL OUTER JOIN
子句 - MySQL不支持
WITH
子句
此时我束手无策。我想为上述情况编写一个快速高效的查询。这是我的两次尝试(none 有效):
这个不起作用,因为我不能使用 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 提供的解决方案,我能够在大约 500 万行测试数据上测试这两个查询的性能(尽管 user1 = 1 或 user2 = 1 - 远小于此)。
和(联合)
因此。查询 1 快 34% ((3.4-2.24)/3.4*100 = 34).
请注意,此 table 上没有索引。稍后我将尝试使用 MariaDB 进行相同类型的测试并比较结果。
更新 2
索引列后:user1
、user2
、amount
情况发生了变化。
查询 1 运行 时间:
显示第 0 - 2 行(共 3 行,查询耗时 1.9857 秒。)
查询2运行时间:
显示第 0 - 2 行(共 3 行,查询耗时 1.5641 秒。)
但我仍然认为这是一个很糟糕的结果。也许我会把一些触发器更新到专用的 table 中。不过至此答案有了答案。
您可以使用基于 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;