Mysql 创建透支对账单
我目前一直在思考如何创建一个报表,显示特定委员会的每日透支报表 我有以下内容:委员会、用户、市场、市场交易、用户存款 市场交易每天运行,减少用户帐户余额。当账户余额为0时,用户将进入负透支状态。当用户存款时,他们的帐户余额会增加 我用下表来说明交易和存款是如何存储的。 如果我撤销今天的交易,我就能够得到用户昨天的账户余额,但制定查询以获得每日OD金额才是问题所在 使用者 用户id 名称 帐户余额 1. 井 -5 2. 詹姆斯 100 3. 快乐 10 4. 蒙比 -300Mysql 创建透支对账单,mysql,sql,database,Mysql,Sql,Database,我目前一直在思考如何创建一个报表,显示特定委员会的每日透支报表 我有以下内容:委员会、用户、市场、市场交易、用户存款 市场交易每天运行,减少用户帐户余额。当账户余额为0时,用户将进入负透支状态。当用户存款时,他们的帐户余额会增加 我用下表来说明交易和存款是如何存储的。 如果我撤销今天的交易,我就能够得到用户昨天的账户余额,但制定查询以获得每日OD金额才是问题所在 使用者 用户id 名称 帐户余额 1. 井 -5 2. 詹姆斯 100 3. 快乐 10 4. 蒙比 -300 这其实没那么难,但你问
这其实没那么难,但你问的方式让人很难理解 此外,您的预期结果应该与您提供的数据相匹配 编辑:以前的解决方案是错误的-如果每个用户/日期有多个事件,它会多次计算提款和存款 从每天交换总数开始,如
select user_id, date, sum(amount) exchanged_on_day from (
select user_id, date, amount amount from deposits
union all select user_id, date, -amount_tendered amount from transactions
) d
group by user_id, date
order by user_id, date;
以下内容仅在有任何存款或取款的日期获取帐户状态。
要获得所有日期的结果,而不仅仅是那些帐户移动的结果,您只需更改交叉连接部分,就可以得到一个包含所有日期的表,但我偏离了主题
select dates.date, c.council_id, u.name username
, u.account_bal - sum(case when e.date >= dates.date then e.exchanged_on_day else 0 end) as amount_on_start_of_day
, u.account_bal - sum(case when e.date > dates.date then e.exchanged_on_day else 0 end) as amount_on_end_of_day
from councils c
inner join markets m on c.council_id=m.council_id
inner join market_user_link mul on m.market_id=mul.market_id
inner join users u on mul.user_id=u.user_id
left join (
select user_id, date, sum(amount) exchanged_on_day from (
select user_id, date, amount amount from deposits
union all select user_id, date, -amount_tendered amount from transactions
) d group by user_id, date
) e on u.user_id=e.user_id --exchange on each Day
cross join (select distinct date from (select date from deposits union select date from transactions) datesInternal) dates --all days that had a transaction
group by dates.date, c.council_id, u.name, u.account_bal
order by dates.date desc, c.council_id, u.name;
从那里你可以重新安排得到你想要的结果
select date, council_id
, sum(case when amount_on_start_of_day<0 then amount_on_start_of_day else 0 end) o_d_amount_start
, sum(case when amount_on_end_of_day<0 then amount_on_end_of_day else 0 end) o_d_amount_end
from (
select dates.date, c.council_id, u.name username
, u.account_bal - sum(case when e.date >= dates.date then e.exchanged_on_day else 0 end) as amount_on_start_of_day
, u.account_bal - sum(case when e.date > dates.date then e.exchanged_on_day else 0 end) as amount_on_end_of_day
from councils c
inner join markets m on c.council_id=m.council_id
inner join market_user_link mul on m.market_id=mul.market_id
inner join users u on mul.user_id=u.user_id
left join (
select user_id, date, sum(amount) exchanged_on_day from (
select user_id, date, amount amount from deposits
union all select user_id, date, -amount_tendered amount from transactions
) d group by user_id, date
) e on u.user_id=e.user_id --exchange on each Day
cross join (select distinct date from (select date from deposits union select date from transactions) datesInternal) dates --all days that had a transaction
group by dates.date, c.council_id, u.name, u.account_bal
) result
group by date, council_id
order by date;
您可以在上查看,基本上,该查询将用户映射到议会,计算用户的透支周期,它们在议会上聚合。我假设起始余额的日期为“2021-04-01”月初,也可以是期末余额,见下文,根据需要进行更改。此外,负的起始余额也算作透支。为了简单和调试,查询分为若干步骤
with uc as (
select distinct m.council_id, mul.user_id
from markets m
join market_user_link mul on m.market_id = mul.market_id
),
user_running_total as (
select user_id, date,
coalesce(lead(date) over(partition by user_id order by date) - interval 1 day, date) nxt,
sum(sum(s)) over(partition by user_id order by date) rt
from (
select user_id, date, -amount_tendered s
from transactions
union all
select user_id, date, amount
from deposits
union all
select user_id, se.d, se.s
from users
cross join lateral (
select date(NOW() + interval 1 day) d, 0 s
union all
select '2021-04-01' d, account_bal
) se
) t
group by user_id, date
),
user_overdraft as (
select user_id, date, nxt, least(rt, 0) ovd
from user_running_total
where date <= date(NOW())
),
dates as (
select date
from user_overdraft
union
select nxt
from user_overdraft
),
council__overdraft as (
select uc.council_id, d.date, sum(uo.ovd) total_overdraft, lag(sum(uo.ovd), 1, sum(uo.ovd) - 1) over(partition by uc.council_id order by d.date) prev_ovd
from uc
cross join dates d
join user_overdraft uo on uc.user_id = uo.user_id and d.date between uo.date and uo.nxt
group by uc.council_id, d.date
)
select council_id, date, total_overdraft
from council__overdraft
where total_overdraft <> prev_ovd
order by date, council_id
按日期排序的存款,为最后一个日期添加了额外的行
id user_id amount date
3 3 5 2021-04-25
4 4 5 2021-04-25
1 1 5 2021-04-26
2 3 10 2021-04-26
5 3 73 2021-05-06
按日期排序的事务,请注意添加的行,以说明正在运行的总计
id user_id amount_tendered date
5 4 50 2021-04-25
2 2 10 2021-04-26
3 3 15 2021-04-26
1 1 5 2021-04-27
4 3 17 2021-04-27
理事会
council_id name
1 a
2 b
3 c
市场
market_id name council_id
1 x 3
2 y 1
3 z 2
市场用户链接
id market_id user_id
1 1 3
2 2 2
3 3 1
4 3 4
查询输出为
理事会
日期
透支
1.
2021-04-01
0
2.
2021-04-01
-305
3.
2021-04-01
0
2.
2021-04-25
-350
2.
2021-04-26
-345
2.
2021-04-27
-350
3.
2021-04-27
-7
3.
2021-05-06
0
MySQL!=SQL Server-请更正您的标记。@您的输出与给定的示例数据不匹配,您的示例数据是4月24日及以后的,而您的输出显示的是4月1日和2日,而不是usefull@eshirvana,好吧,我希望它能帮助说明最终目标,但我已经更新了它们以适应日期您的MARKET\u USER\u LINK.MARKET\u id列似乎是错误的;它应该包含整数。您应该使用诸如db-fiddle.com之类的站点来定义和初始化这些具有正确数据的表。有关输出中显示的透支金额,请参见。@Wells,我看不出如何使用给定的样本数据计算透支金额。用英语解释一个给定的示例数据hey@Serg,感谢您提供额外的测试用例,在我的解决方案中发现了一个错误。我想你弄错了,因为问题是,如果我撤销今天的交易,我就能得到用户昨天的账户余额——这意味着起始余额的日期在事件表的最后日期之后。@BrunoCanettieri。。添加了当users表持有结账时的查询版本,现在是余额。谢谢你的观点。嘿@Serg,如果最后一天透支是-305,那么前一天不可能是-5,因为没有足够大的操作来实现这一点。问题是,在您的内部查询中,当没有操作时,没有用户/天的rt余额行-然后您的最终查询将其视为零。@BrunoCanettieri,。。谢谢,没错。添加了日期步骤,更多测试数据。我添加了更多示例数据,您可能希望使用新数据测试您的解决方案。@Serg,谢谢。不同的是,你在每天的开始显示透支。我的查询中的一个简单更改会得到与您相同的结果,使用>as explained correction,使用>=您的意思是当e.date>=dates.date时的sumcase吗?不,约会还是不同的。我的查询列出了一天结束时的透支。例如,委员会3由单个用户3组成。因此,当用户3在2021-04-27花费17英镑时,我的查询将列出委员会3:2021-04-26-46; 2021-04-27 -63. 当用户在2021-05-06存款73时,我的查询显示那天的透支为0。您的查询在一天结束时列出了结果,这是对的,我的错误。但我们的结果是一样的。我已经更新了我的答案,以便db fiddle使用与您提供的相同的测试数据。现在的差异只是因为您添加了一个额外的日期2021-04-01。还是我没有看到明显的东西?
id market_id user_id
1 1 3
2 2 2
3 3 1
4 3 4