我想知道两个不同日期结束时的余额差异(余额比较)。
我在 MS-Access 2003版本(DATABASE VERSION Access2000)中有以下表结构:
CreditID TxnDate PartyID TxnType 量 评论
DebitID TxnDate PartyID TxnType 量 评论
PartyID PartyName PartyAddress PartyContactNo 描述
我使用VB6和ADO2运行下面的QUERY,以便在两个不同日期的末尾获得账户余额,以进行比较。
。
SELECT P.PartyID, P.PartyName,
IIF((SELECT SUM(C.Amount) FROM Credits C WHERE C.PartyID = P.PartyID AND C.TxnDate <= "#31/07/2014#") IS NULL,0,(SELECT SUM(C.Amount) FROM Credits C WHERE C.PartyID = P.PartyID AND C.TxnDate <= "#31/07/2014#"))
-
IIF((SELECT SUM(D.Amount) FROM Debits D WHERE D.PartyID = P.PartyID AND D.TxnDate <= "#31/07/2014#") IS NULL, 0, (SELECT SUM(D.Amount) FROM Debits D WHERE D.PartyID = P.PartyID AND D.TxnDate <= "#31/07/2014#")) AS BalanceOn31Jul2014,
IIF((SELECT SUM(C.Amount) FROM Credits C WHERE C.PartyID = P.PartyID AND C.TxnDate <= "#31/08/2014#") IS NULL, 0, (SELECT SUM(C.Amount) FROM Credits C WHERE C.PartyID = P.PartyID AND C.TxnDate <= "#31/08/2014#"))
-
IIF((SELECT SUM(D.Amount) FROM Debits D WHERE D.PartyID = P.PartyID AND D.TxnDate <= "#31/08/2014#") IS NULL, 0, (SELECT SUM(D.Amount) FROM Debits D WHERE D.PartyID = P.PartyID AND D.TxnDate <= "#31/08/2014#")) AS BalanceOn31Aug2014
FROM Parties AS P
ORDER BY PartyName;
上面的查询运行但是很慢。
我想知道有没有优化上面的QUERY?
答案 0 :(得分:1)
我认为使用group by
一次性计算所有点数和借记会更快:
select
c.PartyID,
c.PartyName,
Nz(c.Credit31Jul2014, 0) - Nz(d.Debit31Jul2014, 0) as BalanceOn31Jul2014,
Nz(c.Credit31Aug2014, 0) - Nz(d.Debit31Aug2014, 0) as BalanceOn31Aug2014
from (
select
p.PartyID,
p.PartyName,
sum(iif(c.TxnDate <= #31/07/2014#, c.amount, 0)) as Credit31Jul2014,
sum(iif(c.TxnDate <= #31/08/2014#, c.amount, 0)) as Credit31Aug2014
from
Parties p
left outer join
Credits c
on p.PartyID = c.PartyID
group by
p.PartyID,
p.PartyName
) c left outer join (
select
d.PartyID,
sum(iif(d.TxnDate <= #31/07/2014#, d.amount, 0)) as Debit31Jul2014,
sum(iif(d.TxnDate <= #31/08/2014#, d.amount, 0)) as Debit31Aug2014
from
Debits d
where
d.TxnDate <= #31/08/2014#
group by
d.PartyID
) d on c.PartyID = d.PartyID
order by
c.PartyName;
您可能需要考虑存储余额表,以便在不同日期(例如每月一次)保持派对余额。这将限制你必须总结的时间间隔。
要知道为什么它很快。首先,对于您的查询,您实际上每个PartyID至少运行4次,可能是8次选择。您可以使用Nz(sum(xxx), 0)
代替Iif(sum(xxx) is null, 0, sum(xxx))
来略微简化。这将仅保证4.这些选择中的每一个都需要读取整个信用卡或借记卡表。现在,请孤立地考虑我的查询的这一部分:
select
d.PartyID,
sum(iif(d.TxnDate <= #31/07/2014#, d.amount, 0)) as Debit31Jul2014,
sum(iif(d.TxnDate <= #31/08/2014#, d.amount, 0)) as Debit31Aug2014
from
Debits d
where
d.TxnDate <= #31/08/2014#
group by
d.PartyID
这可以获得每方的总借记。想象一下,给一个分类账并被要求计算这个。您可以使用笔记本来保留部分结果。您可以依次阅读每个分类帐项目,如果它符合您在笔记本中查看的日期条件,以查看您是否有此方的记录。如果没有,您将添加一行与行中的金额。如果您这样做,您将使用金额加上行中的金额替换金额。要意识到的关键是,只需阅读一次分类帐就可以做到这一切。使用您的方法,您每方都会多次阅读分类帐。
答案 1 :(得分:0)
我在代码的第4行和第5行修改了劳伦斯对AVOID Nz / IIf的回答。
感谢劳伦斯,没有他,我现在无法重新回答这个问题。
因此我使用的最终代码是
SELECT cc.PartyID, cc.PartyName,
(cc.Credit31Jul2014 - dd.Debit31Jul2014) AS BalanceOn31Jul2014,
(cc.Credit31Aug2014 - dd.Debit31Aug2014) AS BalanceOn31Aug2014
FROM
(SELECT p.PartyID, p.PartyName,
SUM(IIF(c.TxnDate <= #31/07/2014#, c.amount, 0)) AS Credit31Jul2014,
SUM(IIF(c.TxnDate <= #31/08/2014#, c.amount, 0)) AS Credit31Aug2014
FROM Parties p
LEFT OUTER JOIN Credits c ON p.PartyID = c.PartyID
GROUP BY p.PartyID, p.PartyName) AS cc
LEFT OUTER JOIN
(SELECT p.PartyID,
SUM(IIF(d.TxnDate <= #31/07/2014#, d.amount, 0)) AS Debit31Jul2014,
SUM(IIF(d.TxnDate <= #31/08/2014#, d.amount, 0)) AS Debit31Aug2014
FROM Parties p
LEFT OUTER JOIN Debits d ON p.PartyID = d.PartyID
GROUP BY p.PartyID) AS dd
ON dd.PartyID = cc.PartyID
ORDER BY cc.PartyName;
。 感谢Laurence @Laurence