我有一张这样的表:
+-----------+------------+---------------+-------------+--------------+
| member_id | balance | amount | new_balance | time |
+-----------+------------+---------------+-------------+--------------+
| 5 | 630 | -30 | 600 | 2017-08-14 |
| 3 | 142 | -68 | 74 | 2017-08-14 |
| 3 | 120 | 22 | 142 | 2017-08-13 |
| 3 | 0 | 120 | 120 | 2017-08-12 |
| 20 | 300 | 324 | 624 | 2017-08-12 |
| 4 | 100 | -30 | 70 | 2017-08-11 |
| 4 | 0 | 100 | 100 | 2017-08-10 |
| 5 | 30 | 600 | 630 | 2017-08-10 |
+-----------+------------+---------------+-------------+--------------+
我希望选择的是:
+-----------+------------+---------------+---------------+-------------+
| member_id | balance | in_amount | out_amount | new_balance |
+-----------+------------+---------------+---------------+-------------+
| 3 | 0 | 142 | 0 | 142 |
| 4 | 100 | 0 | -30 | 70 |
| 5 | 630 | 0 | 0 | 630 |
| 20 | 300 | 324 | 0 | 624 |
+-----------+------------+---------------+---------------+-------------+
这是一段时间内的摘要(2017-08-11至2017-08-13)。
余额:期间开始时的余额;
in_amount:期间内正数的总和;
out_amount:期间内负数的总和;
new_balance:期末的余额;
我已经制定了类似的声明,以获得收入和结果:
set @start = "2017-08-11 00:00:00";
set @end = "2017-08-13 00:00:00";
SELECT
DISTINCT(member_id),
sum(if(amount>0, amount, 0)) as in_amount,
sum(if(amount<0, amount, 0)) as out_amount,
FROM transaction
WHERE
(time BETWEEN @start and @end)
group by member_id;
但是,我不知道将余额和new_balance包含在语句中。有人对我有任何建议吗?
答案 0 :(得分:1)
使用两个子查询和LEFT JOIN
。
第一个子查询检索最近的余额。 第二个子查询使用日期参数汇总每个成员的进出金额。
使用LEFT JOIN
可让我们为每位成员获取余额,包括那些未在@start
和@end
之间进行交易的成员
set @start = "2017-08-11 00:00:00";
set @end = "2017-08-13 00:00:00";
select
lastTransaction.member_id,
lastTransaction.balance,
IFNULL(computeInOut.in_amount, 0) as in_amount,
IFNULL(computeInOut.out_amount, 0) as out_amount,
lastTransaction.balance,
-- balance is the most recent balance + computed in amout - computed out amount
(lastTransaction.balance + IFNULL(computeInOut.in_amount, 0) + IFNULL(computeInOut.out_amount, 0)) as new_balance
FROM
( -- retrieving the most recent balance information prior to @start
SELECT
member_id,
max(time) as mostRecentTransaction,
balance
FROM transaction
WHERE time <= @start
group by member_id
) as lastTransaction
LEFT JOIN
( -- calculating in & out amounts sum based on the date parameters
SELECT
member_id,
sum(if(amount>0, amount, 0)) as in_amount,
sum(if(amount<0, amount, 0)) as out_amount
FROM transaction
WHERE
(time BETWEEN @start and @end)
group by member_id
) as computeInOut
ON (lastTransaction.member_id = computeInOut.member_id)
结果:
+-----------+---------+--------+---------+------------+
| member_id | balance | inflow | outflow | newbalance |
+-----------+---------+--------+---------+------------+
| 4 | 100 | 0 | -30 | 70 |
| 5 | 30| 0 | 0 | 30 |
+-----------+---------+--------+---------+------------+
会员5和20不在结果中,因为他们的第一笔交易发生在@start之后,因此事件之前没有余额(11h和13th之间的交易)
答案 1 :(得分:1)
余额字段可以是期间的开头,也可以是期间的第一个日期,因此带有限制的子查询应该找到这些,并且合并可以决定使用哪个。新余额必须是期间中的最后一个日期,因此具有desc order by和limit的子查询应该找到这些。
set @start = "2017-08-11 00:00:00";
set @end = "2017-08-13 00:00:00";
select member_id,
coalesce(
(select t1.balance from t t1 where t1.member_id = t.member_id and t1.dt = @start order by t1.dt desc limit 1)
,(select t1.balance from t t1 where t1.member_id = t.member_id and t1.dt > @start order by t1.dt asc limit 1)
) balance,
sum(case when amount > 0 then amount else 0 end) inflow,
sum(case when amount < 0 then amount else 0 end) outflow,
(select t1.new_balance from t t1 where t1.member_id = t.member_id and t1.dt <= @end order by t.dt desc limit 1) newbalance
from t
where t.dt between @start and @end
group by member_id
结果
+-----------+---------+--------+---------+------------+
| member_id | balance | inflow | outflow | newbalance |
+-----------+---------+--------+---------+------------+
| 3 | 0 | 142 | 0 | 142 |
| 4 | 100 | 0 | -30 | 70 |
| 20 | 300 | 324 | 0 | 624 |
+-----------+---------+--------+---------+------------+
3 rows in set (0.00 sec)
由于期间没有任何事件,因此有5人退出。