[英]Showing balances of transactions for a given user
我有一種情況,我需要顯示每個用戶與其他用戶的余額。
表結構和虛擬數據腳本:
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);
結果:
現在我想總結 user = 1
信息(余額)。 我想看到的結果是這樣的:
user balance
2 10
3 15
4 -25
5 0
現在,我使用的是最新的穩定 MySQL 版本5.7.17-0ubuntu0.16.04.1
。 我有兩個問題:
FULL OUTER JOIN
子句WITH
子句我的手在這一點上被綁住了。 我想為上述情況編寫一個快速有效的查詢。 這是我的兩次嘗試(均無效):
這個不起作用,因為我不能使用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)。
請注意,此表上沒有索引。 稍后我將嘗試使用 MariaDB 進行相同類型的測試並比較結果。
索引列后: user1
, user2
, amount
情況發生了變化。
查詢 1 運行時間:
顯示第 0 - 2 行(共 3 行,查詢耗時 1.9857 秒。)
查詢2運行時間:
顯示第 0 - 2 行(共 3 行,查詢耗時 1.5641 秒。)
但我仍然認為這是一個很糟糕的結果。 也許我會放一些觸發器來更新余額到一個專用表中。 但在這一點上,答案已經有了答案。
您可以使用基於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;
或者兩步聚合:
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;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.