【问题标题】:Optimizing the SQL Query for Calculating account balance优化计算账户余额的 SQL 查询
【发布时间】:2018-05-16 06:30:51
【问题描述】:

我有以下表格,分别是 BankDetails 和 Transactiondetails。使用这两个表,我想得到账户名的当前余额。

表格:

Create table Bankdetails
(
AccName varchar(50),
AccNo int,
OpBal numeric(18,2)
)

Create table Trandetails
(
AccNo int,
Amount numeric(18,2),
Trantype varchar(10)
)

为两个表插入脚本:

insert into Bankdetails values('A', 12345, 30000.00)
insert into Bankdetails values('B', 13345, 30000.00)
insert into Bankdetails values('C', 14545, 30000.00)
insert into Bankdetails values('D', 15045, 30000.00)

insert into Trandetails values(12345, 5000.00, 'Credit')
insert into Trandetails values(13345, 5000.00, 'Debit')
insert into Trandetails values(15045, 5000.00, 'Debit')
insert into Trandetails values(13345, 5000.00, 'Credit')
insert into Trandetails values(12345, 5000.00, 'Debit')
insert into Trandetails values(13345, 5000.00, 'Debit')
insert into Trandetails values(14545, 5000.00, 'Credit')
insert into Trandetails values(15045, 5000.00, 'Debit')
insert into Trandetails values(14545, 5000.00, 'Debit')

输出会是这样的:

AccName Accno    CurrBal
  A     12345   30000.00 
  B     13345   25000.00
  C     14545   30000.00
  D     15045   20000.00

我需要使用上述两个表格的帐户持有人姓名、帐户编号和当前余额。

以下是我的查询,我想获得优化的查询,即尽可能不使用子查询。 注意:在我的例子中,贷方 = 添加到账户的金额,借方 = 从账户中扣除的金额。

Select bd.accname, bd.accno, 
(bd.opbal - isnull((select SUM(Amount) from Trandetails where Trantype = 'Debit' and accno = bd.accno group by accno),0) + isnull((select SUM(Amount) from Trandetails where Trantype = 'Credit'  and accno = bd.accno group by accno),0)) as Bal
From Bankdetails BD inner join Trandetails TD on td.AccNo = bd.AccNo
group by bd.accno, bd.accname, bd.opbal

对于没有遵循正确的表格命名约定,我深表歉意。任何帮助将不胜感激。

谢谢,

帕雷什·J

【问题讨论】:

  • 我通常会推荐,而不是让 TranType 列只允许 Amount 列包含正值和负值并使用约定(例如,正数是贷方,负数是借方) .它使最有用的查询变得更加容易。否则,在您当前的设计中,您可能会缺少一个 CHECK constraint 来防止 Amount 成为负面的 - 除非您希望人们应用负面信用?
  • @Damien_The_Unbeliever:TranType 一直用于捕获交易类型。在实际表中,它包含更多详细信息,而不仅仅是 CREDIT & Debit。因此不能从表中删除这些列。
  • @Damien_The_Unbeliever:还有其他可能的优化解决方案吗?我的意思是不太复杂的查询。
  • 在这种情况下,我仍然会推荐适当的 CHECK 约束 - 并且可能仍然 store 借记为负数,贷记为正数 - 就像我说的那样,它会产生大多数查询如果您可以简单地SUM 金额列,在这些表格上会容易得多。

标签: sql sql-server sql-server-2008


【解决方案1】:

这个想法是首先为每个交易类型生成总和,DebitCredit。这样,将其加入Bankdetails 以计算当前余额。

;with cte as(
    select
        AccNo,
        Credit = sum(case when TranType = 'Credit' then Amount else 0 end),
        Debit = sum(case when TranType = 'Debit' then Amount else 0 end)
    from Trandetails
    group by
        AccNo
)
select
    bd.AccName,
    bd.AccNo,
    CurrBal = bd.opBal - c.Debit + c.Credit
from BankDetails bd
inner join cte c
    on c.Accno = bd.Accno

【讨论】:

    【解决方案2】:

    对于那些关心性能的人来说,这里是;

    Select   B.AccName
            ,B.AccNo
            ,(B.OpBal + SUM( Case When TranType = 'Credit' Then Amount Else Amount* -1 End)) CurrBal
    From Bankdetails B
    Left Join Trandetails T
    On B.AccNo = T.AccNo
    Group By B.AccName, B.AccNo, B.OpBal;
    

    SQL Fiddle

    【讨论】:

      【解决方案3】:
      SELECT 
          Bankdetails.AccName
          , Bankdetails.AccNo
          , Bankdetails.OpBal 
              + SUM(CASE WHEN TranType = 'Credit' THEN  Amount ELSE 0 END)
              - SUM(CASE WHEN TranType = 'Debit' THEN  Amount ELSE 0 END)
          AS 'CurrBal'
      FROM Trandetails
          INNER JOIN Bankdetails ON Bankdetails.AccNo = Trandetails.AccNo
      GROUP BY Bankdetails.AccNo, Bankdetails.AccName
      

      【讨论】:

      • 如果你能解释你的代码就好了。这将有助于 OP 以及其他 SO 用户。 :)
      • 上述解决方案存在几个错误。 1. 列名“AccNo”不明确。 2. 列“Bankdetails.AccName”在选择列表中无效,因为您没有在 GROUP BY 中包含其他列名
      • 在 Group by 中仍然缺少 Bankdetails.OpBal
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-21
      • 2016-09-23
      • 1970-01-01
      • 2022-10-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多