我有这张表和样本数据,我想计算期初和期末余额。我希望它在6列中
即CreditOpening
,DebitOpening
,Credit
,Debit
,CreditClosing
,DebitClosing
这是表结构和样本数据 删除表事务;
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都有借方金额,它将从借方中减去贷方。
答案 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的查询时,结果是:
对于2018-08-25至2018-08-26,结果集为:
从技术上讲,您可以在没有CTE的情况下执行此操作;您只需要使用WHERE
子句而不是ClosingDebit
来确定要包括哪些帐户,就必须分别定义ClosingCredit
和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),
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版本更易于阅读和理解,但是您的学习目标可能会有所不同。