期初和期末余额总和

时间:2018-08-28 11:38:53

标签: sql sql-server

我有这张表和样本数据,我想计算期初和期末余额。我希望它在6列中

CreditOpeningDebitOpeningCreditDebitCreditClosingDebitClosing

这是表结构和样本数据 删除表事务;

CREATE TABLE Transactions
(
ID INT, 
COATitle VARCHAR(35),
ConfigurationCode INT, 
DebitAmount NUMERIC, 
CreditAmount NUMERIC,
TransactionDate Date
)

INSERT INTO Transactions VALUES (1, 'Sales', 24, '2400', NULL, '2018-08-24');
INSERT INTO Transactions VALUES (2, 'Items', 24, NULL, '1200', '2018-08-24');
INSERT INTO Transactions VALUES (3, 'Bank', 24, NULL, '1200', '2018-08-24');
INSERT INTO Transactions VALUES (4, 'Meezan', 24, '1500', NULL, '2018-08-25');
INSERT INTO Transactions VALUES (5, 'Items', 24, NULL, '1500', '2018-08-25');
INSERT INTO Transactions VALUES (6, 'Bank', 24, NULL, '1200', '2018-08-26');
INSERT INTO Transactions VALUES (7, 'Sales', 24, '5400', NULL, '2018-08-26');
INSERT INTO Transactions VALUES (8, 'Items', 24, NULL, '1200', '2018-08-26');
INSERT INTO Transactions VALUES (9, 'Bank', 24, NULL, '3000', '2018-08-26');

我有这个查询,其输出如下:

;WITH CTE AS (
    SELECT *
    FROM 
    Transactions

)
SELECT 
COATitle, SUM([D].[DebitAmount]) DrAmount, SUM([D].[CreditAmount]) CrAmount

FROM(
    SELECT *,
            SUM(ISNULL(NULLIF(DebitAmount, 0), 0)-ISNULL(NULLIF(CreditAmount, 0), 0)) OVER (PARTITION BY CONFIGURATIONCODE ORDER BY ID) as Amount
    FROM CTE
    WHERE [TransactionDate] BETWEEN CAST('Aug 25 2018 11:21AM' AS DATE) AND CAST('Aug 25 2018 11:21AM' AS DATE)

    )D

    GROUP BY COATitle

输出:

COATitle    DrAmount    CrAmount
Items       NULL        1500
Meezan      1500        NULL

现在数据应该看起来像这样

COATitle    OpeningDebit  OpeningDebit  DrAmount  CrAmount  ClosingDebit  ClosingCredit  
Bank        0             0             NULL      1200      0             1200
Items       0             0             NULL      1200      0             1200
Sales       0             0             2400      NULL      2400             0

但是一旦我在日期25和26之间运行查询,结果应该是这样的

COATitle    OpeningDebit  OpeningCredit  DrAmount  CrAmount  ClosingDebit  ClosingCredit  
Bank        0             1200           NULL     4200      0             5400
Items       0             1200           NULL     2700      0             3900
Sales       0             0              5400     NULL      7800             0
Meezan      0             0              1500     NULL      1500             0

Meezan将没有期初余额,因为前一天没有。现在,如果以前在任何日期获得贷方的任何COATitle都有借方金额,它将从借方中减去贷方。

3 个答案:

答案 0 :(得分:1)

在这种情况下,您不需要CTE。这是多余的。 您无需将字符串中的日期转换为日期数据类型。只需以ISO格式YYYY-MM-DD指定日期即可。

我可能是错的,但您的预期数据与示例数据不匹配。

注意:我不确定查询中的ConfigurationCode,因为我不确定该列如何影响您的需求。

DECLARE @Date_Fr    DATE    = '2018-08-25',
        @Date_To    DATE    = '2018-08-25'

SELECT  t.COATitle, 
        OpeningDebit    = ISNULL(o.OpeningDebit, 0), 
        OpeningCredit   = ISNULL(o.OpeningCredit, 0),
        t.DrAmount, t.CrAmount,
        ClosingDebit    = ISNULL(o.OpeningDebit, 0) + t.DrAmount,
        ClosingCredit   = ISNULL(o.OpeningCredit, 0) + t.CrAmount
FROM    (
            SELECT  COATitle, 
                    DrAmount    = SUM(CASE WHEN [TransactionDate] >= @Date_Fr THEN DebitAmount ELSE 0 END), 
                    CrAmount    = SUM(CASE WHEN [TransactionDate] >= @Date_Fr THEN CreditAmount ELSE 0 END)
            FROM    Transactions t
            WHERE   [TransactionDate]       <= @Date_To
            GROUP BY COATitle
        ) t
        OUTER APPLY
        (
            SELECT  OpeningDebit    = SUM(DebitAmount), OpeningCredit = SUM(CreditAmount)
            FROM    Transactions x
            WHERE   x.COATitle  = t.COATitle
            AND     x.[TransactionDate] < @Date_Fr
        ) o
WHERE   o.OpeningDebit  IS NOT NULL
OR      o.OpeningCredit iS NOT NULL

答案 1 :(得分:1)

这可能会有所帮助。我进行了额外的检查,因为我不知道例如期初余额为借方余额而贷方为贷方余额的情况是否有效。

DECLARE 
    @from date = '25-08-2018',
    @to date = '26-08-2018'
;

WITH Items (COATitle) AS (
    SELECT DISTINCT COATitle
    FROM dbo.[Transactions]
), OpeningBalance (COATitle, OpeningAmount) AS (
    SELECT COATitle, SUM(ISNULL(DebitAmount, 0)) - SUM(ISNULL(CreditAmount, 0))
    FROM dbo.[Transactions]
    WHERE TransactionDate < @from
    GROUP BY COATitle
), DebitCredit(COATitle, DebitAmount, CreditAmount)  AS (
    SELECT COATitle, SUM(ISNULL(DebitAmount, 0)), SUM(ISNULL(CreditAmount, 0))
    FROM dbo.[Transactions]
    WHERE (@from <= TransactionDate) AND (TransactionDate <= @to)
    GROUP BY COATitle
)
SELECT 
    i.COATitle,
    OpeningDebitAmount = (CASE WHEN SUM(ISNULL(ob.OpeningAmount, 0)) < 0 THEN 0 ELSE SUM(ISNULL(ob.OpeningAmount, 0)) END),
    OpeningCreditAmount = (CASE WHEN SUM(ISNULL(ob.OpeningAmount, 0)) < 0 THEN -SUM(ISNULL(ob.OpeningAmount, 0)) ELSE 0 END),
    DebitAmount = SUM(ISNULL(dc.DebitAmount, 0)), 
    CreditAmount = SUM(ISNULL(dc.CreditAmount, 0)),
    ClosingDebitAmount = (CASE WHEN SUM(ISNULL(ob.OpeningAmount,0)+ISNULL(dc.DebitAmount,0)-ISNULL(dc.CreditAmount, 0)) < 0 THEN 0 ELSE SUM(ISNULL(ob.OpeningAmount,0)+ISNULL(dc.DebitAmount,0)-ISNULL(dc.CreditAmount, 0)) END),
    ClosingCreditAmount = (CASE WHEN SUM(ISNULL(ob.OpeningAmount,0)+ISNULL(dc.DebitAmount,0)-ISNULL(dc.CreditAmount, 0)) < 0 THEN -SUM(ISNULL(ob.OpeningAmount,0)+ISNULL(dc.DebitAmount,0)-ISNULL(dc.CreditAmount, 0)) ELSE 0 END)
FROM Items i
LEFT JOIN OpeningBalance ob ON (i.COATitle = ob.COATitle)
LEFT JOIN DebitCredit dc ON (i.COATitle = dc.COATitle)
GROUP BY i.COATitle

答案 2 :(得分:1)

这是您的可能解决方案。首先,示例数据:

declare @Transactions table
(
    ID int, 
    COATitle varchar(35),
    ConfigurationCode int, 
    DebitAmount money, 
    CreditAmount money,
    TransactionDate date
);

insert @Transactions values
    (1, 'Sales', 24, 2400, NULL, '20180824'),
    (2, 'Items', 24, NULL, 1200, '20180824'),
    (3, 'Bank', 24, NULL, 1200, '20180824'),
    (4, 'Meezan', 24, 1500, NULL, '20180825'),
    (5, 'Items', 24, NULL, 1500, '20180825'),
    (6, 'Bank', 24, NULL, 1200, '20180826'),
    (7, 'Sales', 24, 5400, NULL, '20180826'),
    (8, 'Items', 24, NULL, 1200, '20180826'),
    (9, 'Bank', 24, NULL, 3000, '20180826');

这里要注意几件事。就像您在原始问题中所做的那样,无需使用引号来分隔数字文字,并且我通常建议不要使用numeric数据类型,而无需明确指定精度和小数位数。我选择了money类型的借方和贷方金额。

接下来,我将使用几个局部变量来控制查询的操作。对于您的第一个测试用例,我们将使用:

declare @BeginDate date = '20180801';
declare @EndDate date = '20180824';

这是实现:

with RawDataCTE as
(
    select
        T.COATitle,
        OpeningDebit = coalesce(sum(case when T.TransactionDate < @BeginDate then T.DebitAmount end), 0),
        OpeningCredit = coalesce(sum(case when T.TransactionDate < @BeginDate then T.CreditAmount end), 0),
        DrAmount = sum(case when T.TransactionDate between @BeginDate and @EndDate then T.DebitAmount end),
        CrAmount = sum(case when T.TransactionDate between @BeginDate and @EndDate then T.CreditAmount end)
    from
        @Transactions T
    group by
        T.COATitle
)
select
    R.COATitle,
    R.OpeningDebit,
    R.OpeningCredit,
    R.DrAmount,
    R.CrAmount,
    ClosingDebit = R.OpeningDebit + coalesce(R.DrAmount, 0),
    ClosingCredit = R.OpeningCredit + coalesce(R.CrAmount, 0)
from
    RawDataCTE R
where
    R.OpeningDebit > 0 or
    R.OpeningCredit > 0 or
    R.DrAmount > 0 or
    R.CrAmount > 0;

CTE将所有内容按COATitle进行分组,并且根据我从您期望的结果中得出的假设,期初余额会产生非空结果,但对于借方余额中的借方和贷方总和,可能会产生空结果所需的时间范围。 CTE不会尝试决定应该包括或排除哪些COATitle记录,因为我们需要在做出决定之前汇总数据。

CTE外部的查询从CTE数据中建立期末余额,并忽略任何COATitle,这些HAVING在该时间段内没有期初余额且没有进行任何输入(因此也没有期末余额)。当我运行2018-08-01至2018-08-24的查询时,结果是:

enter image description here

对于2018-08-25至2018-08-26,结果集为:

enter image description here

从技术上讲,您可以在没有CTE的情况下执行此操作;您只需要使用WHERE子句而不是ClosingDebit来确定要包括哪些帐户,就必须分别定义ClosingCreditselect T.COATitle, OpeningDebit = coalesce(sum(case when T.TransactionDate < @BeginDate then T.DebitAmount end), 0), OpeningCredit = coalesce(sum(case when T.TransactionDate < @BeginDate then T.CreditAmount end), 0), DrAmount = sum(case when T.TransactionDate between @BeginDate and @EndDate then T.DebitAmount end), CrAmount = sum(case when T.TransactionDate between @BeginDate and @EndDate then T.CreditAmount end), ClosingDebit = coalesce(sum(case when T.TransactionDate <= @EndDate then T.DebitAmount end), 0), ClosingCredit = coalesce(sum(case when T.TransactionDate <= @EndDate then T.CreditAmount end), 0) from @Transactions T group by T.COATitle having sum(case when T.TransactionDate <= @EndDate and (T.DebitAmount > 0 or T.CreditAmount > 0) then 1 else 0 end) > 0; 而不是结果集中其他字段的总和。例如,这将起作用:

{{1}}

我发现CTE版本更易于阅读和理解,但是您的学习目标可能会有所不同。