使用 SQL Server 从多个表中获取期初余额
Posted
技术标签:
【中文标题】使用 SQL Server 从多个表中获取期初余额【英文标题】:Get Opening balance From Multiple Tables Using SQL Server 【发布时间】:2018-09-16 11:34:49 【问题描述】:我已经尝试了很多天并搜索了整个互联网,但找不到我的问题的解决方案,所以这在任何情况下都不是重复的或可能的重复。 好吧,我有三张桌子;
-
客户(Cus_Id、姓名、OpeningBalance)
销售额(S_Id、Cus_Id、日期、发票编号、项目、总计、已收到、余额)
现金簿(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(这就是如何根据日期从客户表和其他表中获取期初余额的诀窍选择。)
这是存储过程:
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 但我想在顶部显示期初余额,如果在选定日期之前没有以前的条目,则它应该显示客户表期初余额在顶部(如果余额为正,则应在 dr else cr 下显示)否则应返回上一行余额作为顶部的期初余额。
【问题讨论】:
。 .请编辑您的问题并提供示例数据和所需的结果。此外,这个问题令人困惑。您说您想要期初余额,但这显然是其中一个表中的一列。为什么不使用它?请把逻辑解释清楚。 我无法确定这个问题是关于如何编写SELECT
查询或如何正确计算期初余额或两者兼而有之?那么它是哪一个,SQL 还是金融?
@GordonLinoff 我已经更新了问题,请看一下。
@JoakimDanielson 我已经在问题中进一步解释了。我需要一个 storedProcedure 来获取包含正确交易记录的分类帐,具体取决于所选日期。
听起来您需要做的就是加入客户表并添加期初余额。当前的存储过程是否有效?只是缺少期初余额吗?
【参考方案1】:
你有一个有趣的问题。 这是我对您的问题的解决方案:
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 表(Sales #2)中添加了一个数据行。 我假设您在 Customer 表中的 OpeningBalance 始终为正(借方),如果它可能是负值(贷方),则必须在代码中进行一些修改,如果您遇到困难,请告诉我.注意:
希望此解决方案对您有用...
【讨论】:
以上是关于使用 SQL Server 从多个表中获取期初余额的主要内容,如果未能解决你的问题,请参考以下文章
如何编写一个查询以从SQL Server中包含类似名称的多个表中获取数据
如何从 SQL Server 中特定数据库的表中获取所有列名?