在Access SQL中优化NOT IN查询

时间:2011-05-31 05:26:17

标签: sql ms-access query-optimization

我是Access的新手,并且正在使用Access 2007。

我正在对数据库进行简单查询,该数据库包含访问研讨会的客户列表。

我想向客户发送提醒,告知客户上次访问后3个月的服务时间。我创建了一个查询,以便能够返回从当月开始访问3个月的客户列表。例如,如果它现在是5月,则3个月前将是3月(包括5月)。

但是,3个月前访问过的客户可能在2个月前再次访问过。例如,客户A来自三月和四月。他的最后一次访问是在4月,因此,如果我在5月份进行查询,不应该出现在结果中,因为他的提醒应该只在6月发出。

我的查询已经解决了这个问题,但是它很慢。它在Access中加载需要一些时间。任何帮助都将在优化它时受到赞赏。

这里唯一重要的字段是Invoice.DebCode,它是数据库中的customersID。还有另一个表DEBTOR,它是客户表及其详细信息。

我使用INNER JOIN,因为我需要在结果中显示客户(债务人)地址和详细信息。

SELECT Invoice.InvNo, Invoice.InvDate, Invoice.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())) )

3 个答案:

答案 0 :(得分:3)

您可以通过调整WHERE子句来显着加快查询速度,以便直接针对日期字段进行比较(即,不通过Month()和Year()函数)。这样做可以让Jet引擎利用你在Invoice.InvDate字段上的索引(你确实将该字段编入索引,对吗?)。

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))

答案 1 :(得分:1)

如下:

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);

你必须调整你的东西,但想法是一个子查询,选择最近的客户访问,然后从中只选择符合你的月标准的记录。

答案 2 :(得分:0)

由于mwolfe02的建议,我设法加快了查询速度。 为了存档和完成,我将在下面解释我的sql语句。

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))

我编辑了底部子查询,因为mwolfe仅检查当月的客户。只有3个月前来的客户才有资格获得提醒。也就是说,他们不能在当月和前一个月之间访问过。

例如,客户A在4月和5月访问过。目前的月份是6月份,因此他没有资格获得提醒,因为他的最后一次访问是在5月。

客户B在4月和6月访问过,因此他没有资格获得提醒,因为他的最后一次访问是在6月。

因此,查询的英文版本将是:

从3个月前的当月最后一天开始收到来自当月和前一个月的客户。

我希望这可以帮助那些遇到同样问题的人。

正如darkjh和mikey建议的那样,我们可以“选择最近的客户访问,然后从中选择只符合您月份标准的记录。”

全部谢谢!