某些行的期初余额有误

时间:2019-03-31 19:23:10

标签: sql sql-server

我要计算业务应用程序的期初余额和期末余额。但是对于某些行,期初余额产生错误。我有以下数据表:

SupplierPayments

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

Expensis

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 2012查询

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.EventDate, 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 coalesce(coalesce(DateOfPayment, DateOfExpense), DateSold) EventDate, 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 order by m.EventDate ASC

输出

EventDate   DateSold ExpenseDate    PaymentDate  Opening  Income Expense Bill   Closing

2018-06-01  NULL        NULL        2018-06-01   0        0      0      13000   -13000
2018-06-19  NULL        NULL        2018-06-19  -13000    0      0      8000    -21000
2018-08-14  NULL        2018-08-14  NULL        -21000    0      2000    0      -23000
2018-09-27  2018-09-27  NULL        NULL        -30000    24000  0       0      -6000 
2019-01-01  2019-01-01  NULL        NULL        -6000     13000  0       0      7000
2019-03-28  2019-03-28  2019-03-28  2019-03-28  7000      10000  2000   3000    12000
2019-03-29  NULL        2019-03-29  2019-03-29  -23000     0     2000   5000   -30000

计算期末余额的公式如下:

Closing = Opening + Income - Expense - Bill

我们可以注意到,日期2018-09-27的期初余额为-30,000,这是错误的。它应该是-23,000。同样,日期2019-03-29的期初结余也是错误的。

必需的结果

EventDate   DateSold ExpenseDate    PaymentDate  Opening  Income Expense Bill   Closing

2018-06-01  NULL        NULL        2018-06-01   0        0      0      13000   -13000
2018-06-19  NULL        NULL        2018-06-19  -13000    0      0      8000    -21000
2018-08-14  NULL        2018-08-14  NULL        -21000    0      2000    0      -23000
2018-09-27  2018-09-27  NULL        NULL        -23000    24000  0       0      1000 
2019-01-01  2019-01-01  NULL        NULL        1000      13000  0       0      14000
2019-03-28  2019-03-28  2019-03-28  2019-03-28  14000     10000  2000   3000    19000
2019-03-29  NULL        2019-03-29  2019-03-29  19000      0     2000   5000   12000

有可能在任何一天都没有出售任何物品,但是有费用或账单付给了供应商,反之亦然。

此外,任何表都可能在同一日期具有两个条目。

1 个答案:

答案 0 :(得分:0)

您的问题位于SUMLAG的按列排序。如果仅从CTE中进行选择,则会发现您未按三个日期(可用)中的任何日期进行排序,而是按指定的顺序对其进行排序。因此,您将在第一列中获得NULL,然后在第二列中获得NULL,等等。您需要做的是尽快在t中引入EventDate,并对其进行排序。

;with xIncome( DateSold, Income ) as (
    select DateSold,isnull(sum(income),0)
    from income group by DateSold
), xSupplierPayments( DateOfPayment,Bill ) as(
    select DateOfPayment,isnull(sum(bill),0) 
    from supplierpayments group by DateOfPayment
), xExpensis( DateOfExpense, Expense ) as(
    select DateOfExpense Date ,isnull(sum(expense),0) 
    from expensis group by Dateofexpense
), t as (
    select i.DateSold
        ,e.DateOfExpense
        ,sp.DateOfPayment
        ,consolidated.date consolidatedDate
        ,i.income
        , e.Expense
        ,sp.Bill
        , sum(isnull(i.income,0)-(isnull(e.Expense,0)+isnull(sp.Bill,0))) over (order by consolidated.date) as closing_balance 
    from xincome i 
    full outer  join xexpensis e on e.DateOfExpense = i.DateSold 
    full outer join xSupplierPayments sp on sp.DateOfPayment=e.DateOfExpense
    cross apply (select coalesce(i.DateSold,e.DateOfExpense,sp.DateOfPayment) as date) consolidated

) 
select consolidatedDate, 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 consolidatedDate
        ,DateSold
        ,DateOfExpense
        ,DateOfPayment
        ,lag(closing_balance,1,0) over (order by consolidatedDate) as opening_balance
        ,Income
        ,Expense
        ,closing_balance
        ,Bill 
    from t
) as m order by m.consolidatedDate ASC

在CTE中,请注意CROSS APPLY,其中我将所有日期COALESCE合并为一个同名日期。我不得不重命名第一个CTE,以匹配您的示例数据表名称,但是您可以理解它的要旨。