MYSQL如何在一个语句中选择sum列值和特定行条目?

时间:2017-09-14 08:19:21

标签: mysql

我有一张这样的表:

+-----------+------------+---------------+-------------+--------------+
| 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包含在语句中。有人对我有任何建议吗?

2 个答案:

答案 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人退出。