开发者

Optimizing NOT IN query in Access SQL

I am new to Access and am using Access 2007.

I am doing a simple query on a database that has a list of customers who visits a workshop.

I want to send out reminders to the customers for their servicing 3 months from the last time they visited. I have created a query to be able to return me the list of customers who has visited 3 months from the current month. For example, if it is May now, 3 months ago would be March (inclusive of May).

However, customers who visited 3 months ago may have visited again 2 months ago. For example, customer A came in March and April. His last visit was in April, and hence, should not appear in the result if I were to run the query in May, as his reminder should only be sent out in June.

My query has taken care of this, however, it is rather slow. It takes some time for it to load in Access. Any help would be appreciated in optimizing it.

The only important field here is Invoice.DebCode which is the customersID in the database. There is another table DEBTOR, which is the table of customers together with their particulars.

I used the INNER JOIN as I need to display the customer(Debtor) address and particulars in the result.

SELECT Invoice.InvNo, Invoice.InvDate, Invoi开发者_JS百科ce.DebCode, Debtor.DebName, Debtor.AddL1, Debtor.AddL2, Debtor.AddL3, Invoice.CarNo, Invoice.ChaNo, Invoice.ExcReason
  FROM Debtor 
  JOIN Invoice ON Debtor.DebCode = Invoice.DebCode
 WHERE Year(InvDate) = Year(Now())   
  AND Month(InvDate) = Month(Now()) - 2
  AND Invoice.DebCode NOT IN (SELECT Invoice.DebCode
                                FROM Invoice
                               WHERE Year(InvDate) = Year(Now()) 
  AND (   (Month(InvDate) = Month(Now()) -1) 
       OR (Month(InvDate) = Month(Now())) )


You can dramatically speed up your query by adjusting your WHERE clauses so that the comparisons get done directly against the date field (ie, without passing it through the Month() and Year() functions). Doing it this way allows the Jet engine to make use of the index you have on the Invoice.InvDate field (you do have that field indexed, right?).

SELECT I.InvNo, I.InvDate, I.DebCode, D.DebName, D.AddL1, D.AddL2, D.AddL3,
       I.CarNo, I.ChaNo, I.ExcReason
FROM Debtor AS D
  INNER JOIN Invoice AS I 
  ON D.DebCode = I.DebCode
WHERE I.InvDate Between DateSerial(Year(Now()), Month(Now()) - 2, 1)
                    And DateSerial(Year(Now()), Month(Now()) - 1, 0)
  AND I.DebCode NOT IN 
(SELECT Invoice.DebCode FROM Invoice
 WHERE Invoice.InvDate > DateSerial(Year(Now()), Month(Now()) - 1, 0))


What about something like:

SELECT a.debcode, a.debname, a.debstuff, b.most_recent AS last_over_three_months
FROM debtor AS a INNER JOIN 
(
SELECT debcode, Max(invdate) AS most_recent
FROM invoice
GROUP BY debcode
)
as b 
ON a.debcode= b.debcode
WHERE (month(now()) - Month(most_recent) >2);

You will have to tweak for your stuff, but the idea is a subquery that select the most recent customer visit and then selects from that only the records that meet your month criteria.


I managed to speed up the query thanks to mwolfe02 suggestion. For archiving and completion sake, I will explain my sql statements below.

SELECT I.InvNo, I.InvDate, I.DebCode, D.DebName, D.AddL1, D.AddL2, D.AddL3,
       I.CarNo, I.ChaNo, I.ExcReason
FROM Debtor AS D
  INNER JOIN Invoice AS I 
  ON D.DebCode = I.DebCode
WHERE I.InvDate Between DateSerial(Year(Now()), Month(Now()) - 2, 1)
                              And         DateSerial(Year(Now()), Month(Now())- 1, 0)

  AND I.DebCode NOT IN 
(SELECT Invoice.DebCode FROM Invoice
 WHERE Invoice.InvDate Between DateSerial(Year(Now()), Month(Now()) - 1, 1)
                                          And         DateSerial(Year(Now()), Month(Now()), 0))

I edited the bottom sub query as mwolfe checked only for customers in the current month. The customers eligible for a reminder only if they came 3 months ago. That is to say, they cannot have visited between the current month and the month before.

For example, customer A visited in April and May. The current month is June, thus he is not eligible for the reminder, as his last visit was in May.

Customer B visited in April and June, thus he is not eligible for the reminder, as his last visit was in June.

Hence, the english version of the query would be:

Get customers who came 3 months ago from the last day of the current month and did not come in the current month and the month before.

I hope this helps anyone who has the same problem.

As darkjh and mikey suggested, we can "select the most recent customer visit and then selects from that only the records that meet your month criteria."

Thanks all!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜