SQL 查询聚合可能不会出现在 WHERE 子句中

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7166626/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-01 11:49:54  来源:igfitidea点击:

SQL Query aggregate may not appear in WHERE clause

sqlsql-serversql-server-2005

提问by Christopher Keeler

I have this SQL statement and SQL Server is giving me the following error:

我有这个 SQL 语句,SQL Server 给了我以下错误:

An aggregate may not appear in the WHERE clause unless it is in a subquery contained in a HAVING clause or a select list.

聚合可能不会出现在 WHERE 子句中,除非它位于包含在 HAVING 子句或选择列表中的子查询中。

SELECT 
  SUM(M1.InvoiceTotal)-SUM(M1.AmountApplied) as PastDueAmount
  , M1.BillingID
  , M2.Name
  , M2.DelinquentDaysThreshold
  , M2.DelinquentAmountThreshold
  , DATEDIFF(d, MIN(BillingDate),GETDATE()) as DaysLate
FROM Invoices M1 
LEFT JOIN ClientAccounts M2 ON M1.BillingID = M2.ID
WHERE 
  InvoiceTotal <> AmountApplied
  AND M2.DelinquentDaysThreshold > DATEDIFF(d, MIN(BillingDate),GETDATE())
  OR (SUM(M1.InvoiceTotal)-SUM(M1.AmountApplied)) > M2.DelinquentAmountThreshold
GROUP BY 
  M1.BillingID
  , M2.Name
  , M2.DelinquentDaysThreshold
  , M2.DelinquentAmountThreshold

In the where clause, I only want to pull records where the oldest unpaid Billing Invoice Date is greater than the DelinquentDaysThreshhold (in days), OR the PastDueAmount (a calculated value) is greater than the DelinquentAmountThreshold.
For some reason SQL Server does not like aggregated amounts.

在 where 子句中,我只想提取最早未付帐单发票日期大于 DelinquentDaysThreshold(以天为单位)或 PastDueAmount(计算值)大于 DelinquentAmountThreshold 的记录。
出于某种原因,SQL Server 不喜欢聚合金额。

回答by gbn

Use the HAVINGas hinted by the error message, which requires a GROUP BY:

使用HAVING错误消息提示的,这需要一个GROUP BY

SELECT
    SUM(M1.InvoiceTotal)-SUM(M1.AmountApplied) as PastDueAmount, 
    M1.BillingID, M2.Name, 
    M2.DelinquentDaysThreshold, M2.DelinquentAmountThreshold,
    DATEDIFF(d, MIN(BillingDate),GETDATE()) as DaysLate
FROM
    Invoices M1
    LEFT JOIN
    ClientAccounts M2 ON M1.BillingID = M2.ID
WHERE
    InvoiceTotal <> AmountApplied
    AND
    M2.DelinquentDaysThreshold > DATEDIFF(d, MIN(BillingDate),GETDATE())
GROUP BY
    M1.BillingID, M2.Name, 
    M2.DelinquentDaysThreshold, M2.DelinquentAmountThreshold,
    DATEDIFF(d, MIN(BillingDate),GETDATE())
HAVING
    (SUM(M1.InvoiceTotal)-SUM(M1.AmountApplied)) > M2.DelinquentAmountThreshold

回答by Matthew

Use "Having" for use with aggregate functions.

使用“Having”与聚合函数一起使用。

Heres a link: http://msdn.microsoft.com/en-us/library/ms180199.aspx

这是一个链接:http: //msdn.microsoft.com/en-us/library/ms180199.aspx

回答by James Johnson

In the where clause, I only want to pull records where the oldest unpaid Billing Invoice Date is greater than the DelinquentDaysThreshhold (in days)

在 where 子句中,我只想提取最早未付帐单发票日期大于 DelinquentDaysThreshhold(以天为单位)的记录

Some performance considerations with the HAVING clause:

HAVING 子句的一些性能注意事项:

When you use GROUP BY with the HAVING clause, the GROUP BY clause divides the rows into sets of grouped rows and aggregates their values, andthen the HAVING clause eliminates undesired aggregated groups. In many cases,you can write your select statement so it will contain only WHERE and GROUP BY clauses without a HAVING clause.

当您将 GROUP BY 与 HAVING 子句一起使用时,GROUP BY 子句将行划分为分组的行集并聚合它们的值,然后 HAVING 子句消除不需要的聚合组。在许多情况下,您可以编写 select 语句,使其仅包含 WHERE 和 GROUP BY 子句,而不包含 HAVING 子句。

As an alternative to the HAVING clause, you can also use derived tables to solve this problem:

作为 HAVING 子句的替代,你也可以使用派生表来解决这个问题:

SELECT t1.SomeID, t1.SomeThreshold, totals.NumericTotal
FROM   Table1 t1
       INNER JOIN (
          SELECT SomeID, SUM(SomeNumericValue) NumericTotal
          FROM Table1
          Group By SomeID
       ) totals
           ON t1.SomeID = totals.SomeID
WHERE totals.NumericTotal > t1.SomeThreshold