Sql 基于多列的升序日期,用于计算期初和期末余额

Sql 基于多列的升序日期,用于计算期初和期末余额,sql,sql-server,sql-server-2012,Sql,Sql Server,Sql Server 2012,我正在为一家商店开发一个应用程序。在该业务中,任何一天都可能没有出售任何物品,但有支付给供应商的费用或账单,反之亦然。期末余额的计算公式如下: Closing_Balance = Opening_Balance + Income - Expense - Bill 我有以下几张表 供应商付款 DateOfPayment Bill 2018-06-01 4000 2018-06-01 9000 2018-06-19 2000 2018-06-19 60

我正在为一家商店开发一个应用程序。在该业务中,任何一天都可能没有出售任何物品,但有支付给供应商的费用或账单,反之亦然。期末余额的计算公式如下:

Closing_Balance = Opening_Balance + Income - Expense - Bill
我有以下几张表

供应商付款

DateOfPayment   Bill

2018-06-01      4000
2018-06-01      9000
2018-06-19      2000
2018-06-19      6000
2019-03-28      3000
2019-03-29      5000
费用

DateOfExpense   Expense

2018-08-14      2,000
2019-02-26      8,000
2019-03-28      2000
2019-03-29      2000
收入

DateSold        Income

2018-09-27      24,000
2018-10-17      8,000
2019-01-01      13,000
2019-03-28      10,000
我用了下列方法 SQL Server查询

with Income( DateSold, Income ) as (
    select DateSold,isnull(sum(TotalBill),0)
    from SalesInvoice group by DateSold
), SupplierPayments( DateOfPayment,Bill ) as(
    select DateOfPayment,isnull(sum(BillPaidAmount),0) 
    from SupplyInvoicePaymentHistory group by DateOfPayment
), Expensis( DateOfExpense, Expense ) as(
    select Date ,isnull(sum(Amount),0) 
    from GeneralExpense group by Date
), t as (
    select i.DateSold
        ,e.DateOfExpense
        ,sp.DateOfPayment
        ,i.income
        , e.Expense
        ,sp.Bill
        , sum(isnull(i.income,0)-(isnull(e.Expense,0)+isnull(sp.Bill,0))) over (order by i.DateSold,e.DateOfExpense,sp.DateOfPayment) as closing_balance 
    from income i 
    full outer  join expensis e on e.DateOfExpense = i.DateSold 
    full outer join SupplierPayments sp on sp.DateOfPayment=e.DateOfExpense

) 
select m.DateSold
    ,m.DateOfExpense
    ,m.DateOfPayment
    ,isnull(m.opening_balance,0) as Opening_Balance
    ,isnull(m.Income,0) as Income
    ,isnull(m.Expense,0) as Expensis
    ,isnull(m.Bill,0) as SupplierPayments
    ,isnull(m.closing_balance,0) as Closing_Balance
from (
    select DateSold
        ,DateOfExpense
        ,DateOfPayment
        ,lag(closing_balance,1,0) over (order by DateSold, DateOfExpense,DateOfPayment) as opening_balance,Income
        , Expense
        ,closing_balance
        ,Bill 
    from t
) as m 
输出

DateSold    ExpenseDate PaymentDate Opening Income  Expense Bill  Closing
NULL         NULL       2018-06-01  0        0      0       4,000 -4,000
NULL         NULL       2018-06-19  -4000    0      0       2,000 -6,000      
NULL        2018-08-14  NULL        -6,000   0      2,000   0     -8,000
NULL        2019-02-26  NULL        -8,000   0      8,000   0     -16,000
NULL        2019-03-29  2019-03-29  -16,000  0      2000    5000  -23,000
2018-09-27  NULL        NULL        -23,000  24,000 0       0     1,000
2018-10-17  NULL        NULL        1,000    8,000  0       0     9,000
2019-01-01  NULL        NULL        9,000    13,000 0       0     22,000
2019-03-28  2019-03-28  2019-03-28  22,000   10,000 2000    3000  27,000
DateSold    ExpenseDate PaymentDate Opening Income  Expense Bill  Closing
NULL        NULL        2018-06-01  0        0      0       4,000 -4,000
NULL        NULL        2018-06-19  -4000    0      0       2,000 -6,000      
NULL        2018-08-14  NULL        -6,000   0      2,000   0     -8,000
2018-09-27  NULL        NULL        -8,000   24,000 0       0     16,000
2018-10-17  NULL        NULL        16,000   8,000  0       0     24,000
2019-01-01  NULL        NULL        24,000   13,000 0       0     37,000
NULL        2019-02-26  NULL        37,000   0      8,000   0     29,000
2019-03-28  2019-03-28  2019-03-28  29,000   10,000 2000    3000  34,000
NULL        2019-03-29  2019-03-29  34,000   0      2000    5000  29,000
由于日期列的顺序不同,
结账
余额错误。我想要以下输出,其中日期是基于3个日期列的升序

要求的结果

DateSold    ExpenseDate PaymentDate Opening Income  Expense Bill  Closing
NULL         NULL       2018-06-01  0        0      0       4,000 -4,000
NULL         NULL       2018-06-19  -4000    0      0       2,000 -6,000      
NULL        2018-08-14  NULL        -6,000   0      2,000   0     -8,000
NULL        2019-02-26  NULL        -8,000   0      8,000   0     -16,000
NULL        2019-03-29  2019-03-29  -16,000  0      2000    5000  -23,000
2018-09-27  NULL        NULL        -23,000  24,000 0       0     1,000
2018-10-17  NULL        NULL        1,000    8,000  0       0     9,000
2019-01-01  NULL        NULL        9,000    13,000 0       0     22,000
2019-03-28  2019-03-28  2019-03-28  22,000   10,000 2000    3000  27,000
DateSold    ExpenseDate PaymentDate Opening Income  Expense Bill  Closing
NULL        NULL        2018-06-01  0        0      0       4,000 -4,000
NULL        NULL        2018-06-19  -4000    0      0       2,000 -6,000      
NULL        2018-08-14  NULL        -6,000   0      2,000   0     -8,000
2018-09-27  NULL        NULL        -8,000   24,000 0       0     16,000
2018-10-17  NULL        NULL        16,000   8,000  0       0     24,000
2019-01-01  NULL        NULL        24,000   13,000 0       0     37,000
NULL        2019-02-26  NULL        37,000   0      8,000   0     29,000
2019-03-28  2019-03-28  2019-03-28  29,000   10,000 2000    3000  34,000
NULL        2019-03-29  2019-03-29  34,000   0      2000    5000  29,000
样本数据:

declare @SupplierPayments table(DateOfPayment date, Bill int);
insert into @SupplierPayments values
('2018-06-01', 4000),
('2018-06-19', 2000),
('2019-03-28', 3000),
('2019-03-29', 5000);

declare @Expensis table(DateOfExpense date, Expense int);
insert into @Expensis values
('2018-08-14',2000),
('2019-02-26',8000),
('2019-03-28',2000),
('2019-03-29',2000);

declare @Income table(DateSold date, Income int);
insert into @Income values
('2018-09-27',24000),
('2018-10-17',8000),
('2019-01-01',13000),
('2019-03-28',10000);
要获得
结束
列,每行使用公式就足够了(无需
打开列
)。 然后,为了获得
结束值
值,在列上使用该公式的累积和就足够了(只需查看查询)。 使用
sum
函数和
over
子句和
order by
可以轻松实现累积和

select EventDate, DateOfExpense, DateOfPayment, DateSold, Income, Expense, Bill,
       sum(Income - Expense - Bill)
         over (order by EventDate rows between unbounded preceding and 1 preceding) Opening,
       sum(Income - Expense - Bill)
         over (order by EventDate) Closing
from (
    select coalesce(coalesce(DateOfPayment, DateOfExpense), DateSold) EventDate, * 
    from (
      select DateOfPayment, sum(coalesce(Bill, 0)) Bill from @SupplierPayments group by DateOfPayment
    ) sp 
    full join (
      select DateOfExpense, sum(coalesce(Expense, 0)) Expense from @Expensis group by DateOfExpense
    ) e on sp.DateOfPayment = e.DateOfExpense
    full join (
      select DateSold, sum(coalesce(Income, 0)) Income from @Income group by DateSold
    ) i on sp.DateOfPayment = i.DateSold
) a order by EventDate

我认为
union all
group by
可能是更好的方法:

select dte, sum(bill) as bill, sum(expense) as expense,
       sum(income) as income,
       sum(income - expense - bill) over (order by dte) - (income - expense - bill) as opening_balance
       sum(income - expense - bill) over (order by dte) as closing_balance
from ((select DateOfPayment as dte, Bill, 0 as expense, 0 as income
       from SupplierPayments
      ) union all
      (select DateOfExpense, 0, Expense, 0 as income
       from expenses
      ) union all
      (select datesold, 0, 0, income
       from income
      )
     ) d
group by dte
order by dte;

该查询比
完全联接
查询简单一些,因为您不必处理太多
NULL
值。更重要的是,如果其中一个表在同一日期有两个条目,这将生成正确的答案。

您使用的是什么版本的SQL?SQL server 2012 OK,那么您可以使用我提出的第一个查询:)但我也需要打开列,请@MichałTurczynUsing SQL server 2012。over子句(窗口函数)可用如果任何表有多个条目,则结果不正确。请相应地修改查询。Thanks@shakeel要解决此问题,您需要在日期中按日期对结果进行分组,以提供日期的唯一性:)检查更新的答案:)如果任何表有两个或多个具有相同日期的记录,仍然无法获得正确的开始和结束。如果任何表有多个条目,则ovpre复杂查询产生错误的期初、期末余额请发送完整查询,生成如我的“必需结果”中所示的结果,具有期初和期末余额请帮助我找出“必需结果”具有期初和期末余额如果其中一个表在同一日期有两个条目,则您的查询也不会生成正确的期初和期末余额。请告诉我正确的查询