SQL WHERE 子句中的聚合函数

在大学的一次考试中有一个问题: 在 SQL WHERE子句中使用聚合函数是否可行。

我一直认为这是不可能的,我也找不到任何可能的例子。但是我的答案是错误的,现在我想知道在哪些情况下可以在 WHERE中使用聚合函数。另外,如果不可能的话,最好获得一个指向描述它的规范的链接。

305238 次浏览

UPDATED query:

select id from t where id < (select max(id) from t);

It'll select all but the last row from the table t.

You haven't mentioned the DBMS. Assuming you are using MS SQL-Server, I've found a T-SQL Error message that is self-explanatory:

"An aggregate may not appear in the WHERE clause unless it is in a subquery contained in a HAVING clause or a select list, and the column being aggregated is an outer reference"

http://www.sql-server-performance.com/


And an example that it is possible in a subquery.

Show all customers and smallest order for those who have 5 or more orders (and NULL for others):

SELECT a.lastname
, a.firstname
, ( SELECT MIN( o.amount )
FROM orders o
WHERE a.customerid = o.customerid
AND COUNT( a.customerid ) >= 5
)
AS smallestOrderAmount
FROM account a
GROUP BY a.customerid
, a.lastname
, a.firstname ;

UPDATE.

The above runs in both SQL-Server and MySQL but it doesn't return the result I expected. The next one is more close. I guess it has to do with that the field customerid, GROUPed BY and used in the query-subquery join is in the first case PRIMARY KEY of the outer table and in the second case it's not.

Show all customer ids and number of orders for those who have 5 or more orders (and NULL for others):

SELECT o.customerid
, ( SELECT COUNT( o.customerid )
FROM account a
WHERE a.customerid = o.customerid
AND COUNT( o.customerid ) >= 5
)
AS cnt
FROM orders o
GROUP BY o.customerid ;

HAVING is like WHERE with aggregate functions, or you could use a subquery.

select EmployeeId, sum(amount)
from Sales
group by Employee
having sum(amount) > 20000

Or

select EmployeeId, sum(amount)
from Sales
group by Employee
where EmployeeId in (
select max(EmployeeId) from Employees)

You can't use an aggregate directly in a WHERE clause; that's what HAVING clauses are for.

You can use a sub-query which contains an aggregate in the WHERE clause.

Another solution is to Move the aggregate fuction to Scalar User Defined Function

Create Your Function:

CREATE FUNCTION getTotalSalesByProduct(@ProductName VARCHAR(500))
RETURNS INT
AS
BEGIN


DECLARE @TotalAmount INT


SET @TotalAmount = (select SUM(SaleAmount) FROM Sales where Product=@ProductName)


RETURN @TotalAmount


END

Use Function in Where Clause

SELECT ProductName, SUM(SaleAmount) AS TotalSales
FROM Sales
WHERE dbo.getTotalSalesByProduct(ProductName)  > 1000
GROUP BY Product

References:

1. 2.

Hope helps someone.

If you are using an aggregate function in a where clause then it means you want to filter data on the basis of that aggregation function. In my case, it's SUM(). I'll jump to the solution.

(select * from(select sum(appqty)summ,oprcod from pckwrk_view group by oprcod)AS asd where summ>500)

  1. The inner query is used to fetch results that need to be filtered.
  2. The aggregate function which has to filter out must be given an ALIAS name because the actual name of the column inside an aggregate function is not accessible or recognized by the outer query.
  3. Finally, the filter can be applied to the aliased name of the column in the inner query

Try this one

select SUM(RecQty) RecQty,ItemCode from
CostLedger group by ItemCode
having sum(RecQty) > 2000