使用SQL Server从多个表中获得期初余额

时间:2018-09-16 11:34:50

标签: sql sql-server

我已经尝试了很多天,并搜索了整个互联网,但是找不到解决我的问题的方法,因此在任何情况下都不能重复或可能重复。 好吧,我有三张桌子;

  1. 客户(客户ID,名称,OpeningBalance)
  2. 销售(S_Id,Cus_Id,日期,发票编号,项目,总计,已接收,余额)
  3. 现金簿(Cb_Id,Acc_Id,日期,描述,PaidAmount,ReceivedAmount)

更新: 添加新客户时,用户可以在“客户”表中输入期初余额,这样我们就可以跟踪在开设客户帐户时的期初余额。因此,为此保留了一列。

现在,我想获取一个客户的分类账,向我显示所选日期之间的交易记录。我的问题是如何获取分别存储在客户表和所有其他表中的期初余额。 我正在共享我使用的存储过程,该存储过程为我提供了来自“销售和现金簿”的正确数据,但我无法获得期初余额,那么在“客户”表中添加新客户时存储的期初余额又如何呢?

  

让我们假设以下情况:   客户表的期初余额为$ 1000.00   首次创建时。他来买了几件值得   $ 200.00,仅支付了$ 50.00,在他回来并支付$ 300的第二天   偿还现金中增加的一些信用额度   由用户预订。现在让我们看看它在分类帐中的外观。

S.No  Date      Description         Dr         Cr        Balance
-----------------------------------------------------------------
                Opening Balance    1000.00    0.00       1000.00
1  16/09/2018   Sales Invoice#1     200.00    0.00       1200.00
2  16/09/2018   Cash Received 
                Against S.Inv#1.    0.00      50.00      1150.00

3  17/09/2018   Cash Book Entry
                Received Cash.      0.00      300.00     850.00
=================================================================

因此,从这个示例中,我希望它明确我想要实现的目标。请注意这一点,如果我想查看2018年9月17日的分类帐,则期初余额应为1150.00而不是1000.00(这是技巧,如何根据日期从Customer表和其他表中获取期初余额选择)。

这是存储过程:

DECLARE @GeneralLedger TABLE
        (
            Id int,
            TransactionDate DATETIME,
            TransactionDescription NVARCHAR(350),
            Dr DECIMAL(18,2),
            Cr DECIMAL(18,2)
        )

        INSERT INTO @GeneralLedger

        SELECT [Acc_Id], [Date], [Description], [PaidAmount], [ReceivedAmount] FROM [CashBook]

        UNION 
        SELECT [Cus_Id], [Date], '(SALES) Invoice# ' + [InvoiceNumber], [Total], CAST(' ' AS INT) FROM [Sales]

        UNION 
        SELECT [Cus_Id], [Date], 'Cash Received Against Sales Invoice# ' + [InvoiceNumber], CAST(' ' AS INT), [Recieved] FROM [Sales]
        Where [Recieved] > 0

        SELECT 
        TransactionDate as 'date',
        TransactionDescription as 'Description',
        Dr as 'Debit',
        Cr as 'Credit',
        SUM(coalesce(Dr, 0) - coalesce(Cr, 0)) OVER (ORDER BY id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS Balance

        FROM @GeneralLedger
        WHERE  TransactionDate >= @FromDate AND TransactionDate <= @ToDate AND id = @AccountTitleId
        GROUP BY
        id,
        TransactionDate,
        TransactionDescription,
        Dr,
        Cr

此存储过程仅适用于计算dr / cr / balance,但我想以以下方式显示期初余额:如果在所选日期之前没有先前的输入,则应显示Customer表期初余额在顶端(如果余额为正,则应在dr博士下显示),否则应返回前一行的余额作为顶端的期初余额。

1 个答案:

答案 0 :(得分:0)

您有有趣的问题。 这是我为您解决的问题:

    ALTER PROCEDURE x1_getCusBalance
        @AccountTitleId int,
        @FromDate smalldatetime,
        @ToDate smalldatetime
    AS
    BEGIN
        declare @GeneralLedger TABLE
            (
                Id int,
                TransactionDate DATETIME,
                TransactionDescription VARCHAR(350),
                Dr DECIMAL(18,2),
                Cr DECIMAL(18,2),
                GroupOrder int
            )

        declare @FirstBalance money = 0
        declare @FirstBalanceDr money = 0
        declare @FirstBalanceCr money = 0
        declare @SalesBalanceDr money = 0
        declare @CashBookBalanceDr money = 0
        declare @SalesBalanceCr money = 0
        declare @CashBookBalanceCr money = 0
        declare @PriorTransBalance money = 0

        -- Calculate Transaction Opening Balance

        SELECT @FirstBalance=OpeningBalance FROM CUSTOMER c
        WHERE
        Cus_id=@AccountTitleId

        SET @FirstBalance=ISNULL(@FirstBalance,0)
        IF @FirstBalance>=0 SET @FirstBalanceDr=@FirstBalance
        IF @FirstBalance<0 SET @FirstBalanceCr=@FirstBalance

        SELECT 
            @SalesBalanceCr=ISNULL(SUM(s.received),0)  
            ,@SalesBalanceDr=ISNULL(SUM(s.total),0)  
        FROM  
            SALES s 
        WHERE 
            Cus_id= @AccountTitleId 
            AND s.[date] <  @FromDate

        SELECT 
            @CashBookBalanceCr=ISNULL(SUM(b.receivedAmount ),0) 
            ,@CashBookBalanceDr=ISNULL(SUM( b.paidAmount),0) 
        FROM  
            CASHBOOK b    
        WHERE 
            Acc_id= @AccountTitleId 
            AND b.[date]  <  @FromDate

        SET @PriorTransBalance=ISNULL(@FirstBalance,0)
        + ABS(ISNULL(@SalesBalanceDr,0)-ISNULL(@SalesBalanceCr,0))
        - ABS(ISNULL(@CashBookBalanceDr,0)-ISNULL(@CashBookBalanceCr,0)) 

        -- Populate temp table

        INSERT INTO @GeneralLedger

        SELECT @AccountTitleId, @FromDate, 'Opening Balance',@PriorTransBalance,0  ,10  

        UNION

        SELECT [Acc_Id], [Date], [Description], [PaidAmount], [ReceivedAmount],20   FROM [CashBook]
        WHERE  
            [Date] BETWEEN  @FromDate AND @ToDate
            AND [Acc_Id] = @AccountTitleId

        UNION 

        SELECT [Cus_Id], [Date], '(SALES) Invoice# ' + [InvoiceNumber], [Total], 0,30 FROM [Sales]
            WHERE  
            [Date] BETWEEN  @FromDate AND @ToDate
            AND [Cus_Id] = @AccountTitleId

        UNION 

        SELECT [Cus_Id], [Date], 'Cash Received Against Sales Invoice# ' + [InvoiceNumber], 0, [Received],40 FROM [Sales]
        WHERE  
            [Date] BETWEEN  @FromDate AND @ToDate
            AND [Cus_Id] = @AccountTitleId
            AND [Received] > 0

        -- Produce Final Result Set 

        SELECT 
            TransactionDate as 'date',
            TransactionDescription as 'Description',
            Dr as 'Debit',
            Cr as 'Credit',
            SUM(coalesce(Dr, 0) - coalesce(Cr, 0)) OVER 
            (ORDER BY id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS Balance
        FROM @GeneralLedger

        GROUP BY
            id,
            TransactionDate,
            GroupOrder,
            TransactionDescription,
            Dr,
            Cr
    END

    /* UnComment and put the following codes in your Select Union statement 
       replacing the 'Opening Balance' Select statement, if you want to see the detail summary 
       of previous transactions balance */
    /*
            SELECT @AccountTitleId, @FromDate, 'Opening Balance Customer'
                ,isnull(@FirstBalanceDr,0)
                ,isnull(@FirstBalanceCr,0)
                ,10  

            UNION
            SELECT @AccountTitleId, @FromDate, 'Prior Sales Transactions'
            , @SalesBalanceDr
            , @SalesBalanceCr
            ,11 

            UNION

            SELECT @AccountTitleId, @FromDate, 'Prior CashBook Transactions'
            ,@CashBookBalanceDr
            ,@CashBookBalanceCr
            ,12  

            UNION
    */
    GO

测试结果:

  

exec x1_getCusBalance 1,'2018-09-16','2018-09-20 23:59:59'

    Result :

    date                     Description                              Debit     Credit  Balance
    ------------------------------------------------------------------------------------------- 
    2018-09-16 00:00:00.000  Opening Balance                          1000.00     0.00  1000.00
    2018-09-16 12:00:00.000  (SALES) Invoice# 1                        200.00     0.00  1200.00
    2018-09-16 12:00:00.000  Cash Received Against Sales Invoice# 1      0.00    50.00  1150.00
    2018-09-17 12:00:00.000  Cash Book Entry Recived Cash                0.00   300.00   850.00
    2018-09-18 12:00:00.000  (SALES) Invoice# 2                        150.00     0.00  1000.00
  

exec x1_getCusBalance 1,'2018-09-17','2018-09-20 23:59:59'

    Result :

    date                    Description                  Debit   Credit Balance
    ---------------------------------------------------------------------------
    2018-09-17 00:00:00.000 Opening Balance              1150.00   0.00 1150.00
    2018-09-17 12:00:00.000 Cash Book Entry Recived Cash    0.00 300.00  850.00
    2018-09-18 12:00:00.000 (SALES) Invoice# 2            150.00   0.00 1000.00
  

exec x1_getCusBalance 1,'2018-09-19','2018-09-20 23:59:59'

    Result :

    date                    Description     Debit   Credit Balance
    --------------------------------------------------------------
    2018-09-19 00:00:00.000 Opening Balance 1000.00   0.00 1000.00

使用的数据:

    CUSTOMER table data : 
       Cus_id Name   OpeningBalance
       ------ ------ ---------------------
       1      Andy   1000,00

    SALES table data :
       S_id  Cus_id Date                InvoiceNumber Item    Total  Received Balance
       ----  ------ ------------------- ------------- ------- ------ -------- -------
       1     1      2018-09-16 12:00:00 1             abc     200,00 50,00    NULL
       2     1      2018-09-18 12:00:00 2             def     150,00 NULL     NULL

    CASHBOOK table data:
       Cb_id Acc_id Date                Description                   PaidAmount ReceivedAmount
       ----- ------ ------------------- ----------------------------- ---------- --------------
       1     1      2018-09-17 12:00:00 Cash Book Entry Received Cash 0,00       300,00
  

注意:

  • 我已在@GeneralLedger临时表中添加了GroupOrder列,以确保“期初余额”列始终显示在最终结果集的顶部。
  • 请确保传递不包含时间部分的@FromDate参数,或使用00:00:00(例如'2018-09-16 00:00:00)和@ToDate,并将时间设置为23:59:59。
  • 我已将最终结果集查询中的WHERE子句重定位到UNION查询中的相应SELECT语句。这只是为了提高查询效率。
  • 我认为您还必须保存日期字段中的时间部分以正确排序结果集
  • 出于测试目的,我在Sales表(第2个销售记录)中添加了一个数据行。
  • 我假设您的“客户中的OpeningBalance”表始终为正(借方),如果可能为负(贷方),则必须对代码进行一些修改,如果您遇到困难,请告诉我。

希望此解决方案对您有用...