SQL:HAVING子句

3

请看以下SQL语句:

SELECT datediff("d", MAX(invoice.date), Now) As Date_Diff
      , MAX(invoice.date) AS max_invoice_date
      , customer.number AS customer_number
FROM invoice 
    INNER JOIN customer 
        ON invoice.customer_number = customer.number
GROUP BY customer.number 

如果添加了以下内容:
HAVING datediff("d", MAX(invoice.date), Now) > 365

这是否只是排除Date_Diff <= 365的行?

HAVING子句在这里应该有什么效果?

编辑:我没有遇到这里答案所说的情况。mdb的副本位于http://hotfile.com/dl/40641614/2353dfc/test.mdb.html(没有宏或病毒)。VISDATA.EXE用于执行查询。

编辑2:我认为问题可能是VISDATA,因为我通过DAO获得了不同的结果。


附加的文件是以Microsoft Access 2.0格式保存的,这可以追溯到1993年。我认为测试您的数据查询没有任何意义,因为我没有那么旧的版本。 - Fionnuala
这是Jet v3.0,因此应该与当前版本兼容。这更多是SQL的问题。 - CJ7
7个回答

5

正如已经指出的那样,是的,这就是效果。为了完整起见,“HAVING”类似于“WHERE”,但是针对已聚合(分组)的值(例如,在此情况下为MAX,或SUM,或COUNT,或任何其他聚合函数)。


1
只是补充一点:发生在分组之前,拥有发生在分组已经发生之后,并且限制了分组的值。 - Jeremy
@Jeremy;是的,这就是我所说的(它正在处理已经聚合的值,即分组后的值)。 - falstro

1
是的,它会排除那些行。

为什么我没有遇到这个问题?这可能与Access中的日期有关吗? - CJ7
不确定,请展示你的数据以及没有“HAVING”子句时得到的输出。 - D'Arcy Rittich

0
那得看你是指表中的行还是结果中的行。 having 子句在分组之后过滤结果,所以它会消除客户而不是发票。
如果你想要过滤掉新发票而不是有新发票的客户,你应该使用 where 条件过滤,在分组之前过滤:
select
  datediff("d",
  max(invoice.date), Now) As Date_Diff,
  max(invoice.date) as max_invoice_date,
  customer.number
from
  invoice 
  inner join customer on invoice.customer_number = customer.number
where
  datediff("d", invoice.date, Now) > 365
group by
  customer.number

目标是仅获取最大发票日期超过365天的客户,我认为可以通过使用HAVING或WHERE(因为使用了MAX)来实现,但我没有得到预期的结果。 - CJ7
@Craig:那么你的查询应该可以工作。如果不行,你应该在其他地方寻找错误。例如,检查日期字段是否实际上是日期而不是文本字段。 - Guffa
是的,我确定 VISDATA(查询工具)是罪魁祸首。它似乎产生了错误的查询结果。 - CJ7

0

我不会使用GROUP BY查询。而是使用标准的Jet SQL:

  SELECT Customer.Number
  FROM [SELECT DISTINCT Invoice.Customer_Number
     FROM Invoice
     WHERE (((Invoice.[Date])>Date()-365));]. AS Invoices 
  RIGHT JOIN Customer ON Invoices.Customer_Number = Customer.Number
  WHERE (((Invoices.Customer_Number) Is Null));

使用SQL92兼容模式:

  SELECT Customer.Number
  FROM (SELECT DISTINCT Invoice.Customer_Number
     FROM Invoice
     WHERE (((Invoice.[Date])>Date()-365));) AS Invoices 
  RIGHT JOIN Customer ON Invoices.Customer_Number = Customer.Number
  WHERE (((Invoices.Customer_Number) Is Null));

关键在于获取一组最近一年内有发票的客户编号,并在该结果集上执行外连接,以仅返回不在最近一年内拥有发票的客户集合中的客户。

1
你对“GROUP BY”有什么反对意见? - CJ7
不必要的。您不需要找出客户发票日期的最大值(Max())或最小值(Min())。您只需要找到在指定期间缺少发票的客户组。此外,对大量记录进行GROUP BY操作可能会非常慢,特别是如果该字段未建立索引。 - David-W-Fenton

0

是的,那就是它会做的。


0

WHERE适用于所有单独的行,因此WHERE MAX(...)将匹配所有行。

HAVING类似于WHERE,但在当前组内。这意味着您可以执行诸如HAVING count(*) > 1之类的操作,这将仅显示具有多个结果的组。

因此,回答您的问题,它只包括记录最高(MAX)日期的组中记录大于365天的行。在这种情况下,您还选择了MAX(date),因此是的,它排除了date_diff <= 365的行。

但是,您可以选择MIN(date)并查看具有大于365的最大日期的所有组中的最小日期。在这种情况下,它不会排除date_diff <= 365的“行”,而是max(date_diff)<= 365的组。

希望这不会太令人困惑...


0

你可能在使用MAX函数时走错了方向。通过对invoice.date列进行MAX操作,实际上是在寻找与客户相关的最近一张发票。因此,HAVING条件实际上是选择所有在过去365天内没有任何发票的客户。

这是你想要做的吗?还是你实际上想要获取所有至少有一张超过一年前的发票的客户?如果是这种情况,那么你应该将MAX函数放在datediff函数之外。


我正在尝试获取在过去365天内没有发票的客户。 - CJ7

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接