英文:
How get subtotals of rows and final value of debt
问题
I'm using Delphi 10.4 and Firebird 3. I have a database with separate tables of incomes, sales, income's payments, sale's payments.
Partners table has 3 fields for storing starting debt of partner at the moment application was installed:
idt
(initial financial debt) if they owe me (for example, 10000)myidt
if I owe them (for example, -10000).idt_date
starting date of debt, for example, debt on 01/01/2020.
Let's suppose I have to calculate the final debt on a specific date, for example, on 20/05/2023.
I must:
- Take the starting debt value (
idt
/myidt
) - Minus sums of incomes in the interval (01/01/2020 - 20/05/2023)
- Plus sums of sales in the interval
- Minus sums of their payments
- Plus sums of my payments
and I get the final debt on 20/05/2023.
My final aim is to get data like this:
Starting debt (01/01/2020): 10,000
Partner_id | DocId | DocDate | Incomes | Sales | Payments | MyPayments | Final Debt |
---|---|---|---|---|---|---|---|
11 | 21 | 05.05.2020 | 500 | 9,500 | |||
11 | 144 | 08.08.2020 | 200 | 9,700 | |||
11 | 205 | 10.04.2021 | 400 | 10,100 | |||
11 | 351 | 15.05.2022 | 2000 | 8,100 | |||
11 | 1025 | 20.05.2023 | 500 | 7,600 |
How may I get such subtotals (debt at a specific time) and the final debt on 20/05/2023?
英文:
I'm using Delphi 10.4 and Firebird 3. I have a database with separate tables of incomes, sales, income's payments, sale's payments.
Partners table has 3 fields for storing starting debt of partner at the moment application was installed :
idt
(initial financial debt) if the owe me (for example, 10000)myidt
if I owe them (for example, -10000).idt_date
starting date of debt, for example debt on 01/01/2020.
Lets suppose I have to calculate final debt on specific date, for example, on 20/05/2023.
I must:
- take starting debt value (
idt
/myidt
) - minus summas of incomes in interval (01/01/2020 - 20/05/2023)
- plus summas of sales in interval
- minus summas of his payments
- plus summas of my payments
and I get final debt on 20/05/2023.
My final aim is get data like this:
starting debt (01/01/2020): 10 000
Partner_id | DocId | DocDate | incomes | sales | payments | MyPayments | final debt |
---|---|---|---|---|---|---|---|
11 | 21 | 05.05.2020 | 500 | 9500 | |||
11 | 144 | 08.08.2020 | 200 | 970 | |||
11 | 205 | 10.04.2021 | 400 | 10100 | |||
11 | 351 | 15.05.2022 | 2000 | 8100 | |||
11 | 1025 | 20.05.2023 | 500 | 7600 |
How may I get such subtotals (debt at specific time) and final debt on 20/05/2023?
It's query what I can write and result table however I know it's not what I expected:
Partner_id | DocId | DocDate | incomes | sales | payments | MyPayments | final debt |
---|---|---|---|---|---|---|---|
11 | 21 | 05.05.2020 | 500 | -500 | |||
11 | 144 | 08.08.2020 | 200 | 200 | |||
11 | 205 | 10.04.2021 | 400 | 400 | |||
11 | 351 | 15.05.2022 | 2000 | -2000 | |||
11 | 1025 | 20.05.2023 | 500 | -500 |
select
Partner_id,
Docid,
DocDate,
Incomes,
Sales,
Payments,
MyPayments,
-coalesce(Incomes,0)+coalesce(Sales,0)-coalesce(Payments,0)+ coalesce(MyPayments,0) as
debt
from
(
Select --incomes
Partner.partner_id,
Incomes.Docid,
Incomes.DocDate,
Incomes.summa as Incomes,
0 as Sales,
0 as Payments,
0 as MyPayments
from Incomes, partners
where
Incomes.partner_id= partners.partner_id and
Partners.partner_id= :partner_id and
Incomes.DocDate>=partners.ifd_date and Incomes.DocDate<=:d
union all
Select --Sales
Partners.partner_id,
Sales.Docid,
Sales.DocDate,
0,
Sales.summa,
0,
0
from Sales, Partners
where
Sales.partner_id=partners.partner_id and
Partners.partner_id= :partner_id and
Sales.Docdate>=partners.ifd_date and Sales.DocDate<=:d
union all
Select --Payments
Partners.partner_id,
Payments.Docid,
Payments.DocDate,
0,
0,
Payments.summa,
0
from Payments, partners
where
Payments.partner_id=partners.partner_id and
Partners.partner_id= :partner_id and
Payments.DocDate>=partners.ifd_dt and Payments.DocDate<=:d
union all
Select --MyPayments
Partners.partner_id,
MyPayments.Docid,
MyPayments.DocDate,
0,
0,
0,
MyPayments.summa
from MyPayments, partners
where
MyPayments.partner_id=partners.partner_id and
Partners.partner_id= :partner_id and
MyPayments.DocDate>=partners.ifd_dt and
MyPayments.DocDate<=:d
) DerivedTable1
答案1
得分: 2
以下是您要翻译的内容:
尝试使用您的测试数据进行此示例
选择
p.Partner_id,partner
,ifd,myifd,ifd_date
,d.Docid,d.DocDate
,d.Oper
,case when oper='Income' then -d.summa end Incomes
,case when oper='Sale' then d.summa end Sales
,case when oper='Payment' then -d.summa end Payments
,case when oper='MyPayment' then d.summa end MyPayments
,d.summa
,(p.ifd+p.myifd)+sum(d.summa)
over(partition by d.partner_id order by d.docdate,d.docid) as tot
从伙伴 p 左连接
( --收入
选择 'Income' as oper,partner_id,Docid,DocDate,-summa as summa 从收入
联合全部
选择 'Sale' as oper,partner_id,Docid,DocDate,summa 从销售
联合全部
选择 'MyPayment' as oper,partner_id,Docid,DocDate,summa 从我的付款
联合全部
选择 'Payment' as oper,partner_id,Docid,DocDate,-summa as summa 从付款
) d on d.partner_id=p.partner_id
其中 d.docdate>=p.ifd_date and d.docdate<=DATE'2023-05-20'
查询结果作为草稿
P.ID | 名称 | IFD | MYIFD | IFD_DATE | DOCID | DOCDATE | OPER | INCOMES | SALES | PAYMENTS | MYPAYMENTS | SUMMA | TOT |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
11 | 公司1 | 10000.00 | 0.00 | 2020-01-01 | 21 | 2020-05-05 | 收入 | 500.00 | null | null | null | -500.00 | 9500.00 |
11 | 公司1 | 10000.00 | 0.00 | 2020-01-01 | 144 | 2020-08-08 | 销售 | null | 200.00 | null | null | 200.00 | 9700.00 |
11 | 公司1 | 10000.00 | 0.00 | 2020-01-01 | 205 | 2021-04-10 | 销售 | null | 400.00 | null | null | 400.00 | 10100.00 |
11 | 公司1 | 10000.00 | 0.00 | 2020-01-01 | 351 | 2022-05-15 | 收入 | 2000.00 | null | null | null | -2000.00 | 8100.00 |
11 | 公司1 | 10000.00 | 0.00 | 2020-01-01 | 1025 | 2022-05-15 | 付款 | null | null | 2000.00 | null | -2000.00 | 6100.00 |
> 为什么要使用 over(partition by d.partner_id order by...) 分析函数
为了计算从第一个文档到当前的累积金额。初始财务债务 + 累积金额 = 当前财务债务
窗口聚合函数 sum(d.summa)over()
- 计算列 d.summa 的当前行和当前行之前的所有行的和,在 按照 docdate 和 docid 排序
- 累积金额。
例如,对于文档 (205,2021-04-10) 累积和为 -500+200+400=100。如果 ifd=10000,则当前余额=10000+100=10100。
另一个文档 (1025,2022-05-15) - 累积金额计算为 -500+200+400-2000-2000=-3900。如果 ifd=10000-3900=6100,则最终债务为6100。
在文档 351 和 1025 日期相同的情况下,需要额外按 DocId 排序。
按照 partner_id 分区是为了分别计算每个合作伙伴的总和。
您可以计算操作类型为 "销售" 的总额
sum(d.sales)over(partition by d.partner_id) as total_sales
这将计算合作伙伴(partner_id)的销售总额。在这种情况下,我们不在 over() 中使用 order 子句 - 计算合作伙伴的总销售额(200+400=600)。
count(*)over(partition by d.partner_id) as total_operations
(=5) 这将计算 partner_id 的行数。
英文:
Try this example, with your test data
select
p.Partner_id,partner
,ifd,myifd,ifd_date
,d.Docid,d.DocDate
,d.Oper
,case when oper='Income' then -d.summa end Incomes
,case when oper='Sale' then d.summa end Sales
,case when oper='Payment' then -d.summa end Payments
,case when oper='MyPayment' then d.summa end MyPayments
,d.summa
,(p.ifd+p.myifd)+sum(d.summa)
over(partition by d.partner_id order by d.docdate,d.docid) as tot
from Partners p left join
( --incomes
Select 'Income' as oper,partner_id,Docid,DocDate,-summa as summa from Incomes
union all
Select 'Sale' as oper,partner_id,Docid,DocDate,summa from Sales
union all
Select 'MyPayment' as oper,partner_id,Docid,DocDate,summa from MyPayments
union all
Select 'Payment' as oper,partner_id,Docid,DocDate,-summa as summa from Payments
) d on d.partner_id=p.partner_id
where d.docdate>=p.ifd_date and d.docdate<=DATE'2023-05-20'
Query result as draft
P.ID | Name | IFD | MYIFD | IFD_DATE | DOCID | DOCDATE | OPER | INCOMES | SALES | PAYMENTS | MYPAYMENTS | SUMMA | TOT |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
11 | Firm1 | 10000.00 | 0.00 | 2020-01-01 | 21 | 2020-05-05 | Income | 500.00 | null | null | null | -500.00 | 9500.00 |
11 | Firm1 | 10000.00 | 0.00 | 2020-01-01 | 144 | 2020-08-08 | Sale | null | 200.00 | null | null | 200.00 | 9700.00 |
11 | Firm1 | 10000.00 | 0.00 | 2020-01-01 | 205 | 2021-04-10 | Sale | null | 400.00 | null | null | 400.00 | 10100.00 |
11 | Firm1 | 10000.00 | 0.00 | 2020-01-01 | 351 | 2022-05-15 | Income | 2000.00 | null | null | null | -2000.00 | 8100.00 |
11 | Firm1 | 10000.00 | 0.00 | 2020-01-01 | 1025 | 2022-05-15 | Payment | null | null | 2000.00 | null | -2000.00 | 6100.00 |
> why does you use over(partition by d.partner_id order by...) analytical function
To calculate accumulated amount from first doc to current. initial financial debt + accumulated amount = current financial debt
Windows aggregate function sum(d.summa)over()
- calculate sum for column d.summa for current row and all rows before current row in order by docdate and docid
- accumulated amount.
For example, with doc (205,2021-04-10) sum -500+200+400=100. with ifd=10000 current balance=10000+100=10100.
Another doc (1025,2022-05-15) - sum calculated as -500+200+400-2000-2000=-3900. with ifd=10000-3900=6100 final debt.
Additional ordering by DocId is necessary for order doc 351 and 1025, when they have same date.
Partitioning by partner_id is necessary to calculate sum for each partner separately.
You can calculate totals for type operation "Sales"
sum(d.sales)over(partition by d.partner_id) as total_sales
this calculates total Sales for partner(partner_id). We do not use in this case order clause in over() - calculate total Sales (200+400=600) for partner.
count(*)over(partition by d.partner_id) as total_operations
(=5) this calculate rows count for partner_id.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论