在两个日期比较A / C余额所需的查询优化[ADO MS-Access Query]

时间:2014-09-13 09:51:50

标签: sql database ms-access query-optimization ado

我想知道两个不同日期结束时的余额差异(余额比较)。

我在 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?

2 个答案:

答案 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