获取行小计和债务的最终值

huangapple go评论69阅读模式
英文:

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&#39;2023-05-20&#39;

查询结果作为草稿

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 的行数。

Fiddle

英文:

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=&#39;Income&#39; then -d.summa end Incomes
     ,case when oper=&#39;Sale&#39; then d.summa end Sales
     ,case when oper=&#39;Payment&#39; then -d.summa end Payments
     ,case when oper=&#39;MyPayment&#39; 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 &#39;Income&#39; as oper,partner_id,Docid,DocDate,-summa as summa  from Incomes
     union all
     Select &#39;Sale&#39; as oper,partner_id,Docid,DocDate,summa  from Sales
     union all
     Select &#39;MyPayment&#39; as oper,partner_id,Docid,DocDate,summa  from MyPayments
     union all
     Select &#39;Payment&#39; as oper,partner_id,Docid,DocDate,-summa as summa from Payments
     ) d on d.partner_id=p.partner_id
    where d.docdate&gt;=p.ifd_date and d.docdate&lt;=DATE&#39;2023-05-20&#39;

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.

Fiddle

huangapple
  • 本文由 发表于 2023年5月21日 05:55:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/76297502.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定