2011-06-11 156 views
50

在大學的測試中存在一個問題;是否可以在SQL WHERE子句中使用聚合函數。SQL中的聚合函數WHERE子句

我一直認爲這是不可能的,我也找不到任何例子如何可能。但我的答案被標記爲false,現在我想知道在哪些情況下可以使用WHERE中的聚合函數。此外,如果這是不可能的,它將很好地鏈接到它所描述的規範。

回答

23

你還沒有提到DBMS。假設您正在使用MS SQL-Server中,我發現了一個T-SQL的錯誤信息是不言自明的:

「聚合不應出現在 WHERE子句,除非它是在一個子查詢 載HAVING子句 或選擇列表,並且列被 聚集在是外部引用」

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


這是一個在子查詢中可能的例子。

顯示爲那些誰擁有5個或以上的訂單(和NULL替他人)所有客戶和最小的順序:

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 ; 

更新。

上面的代碼在SQL Server和MySQL中運行,但是它不返回我期望的結果。下一個更接近。我想這與,GROUPed BY字段和查詢子查詢連接中使用的第一種情況是外部表的PRIMARY KEY有關,而第二種情況則不是。

顯示所有客戶ID和訂單對於那些數誰擁有5或以上的訂單(和NULL替他人):

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 ; 
+0

是的,我沒有提到DBMS,因爲沒有任何指定。它只是說SQL -_- – n3on 2011-06-11 23:48:44

+0

我認爲這種可能性是在SQL-92規範中添加的。不知道什麼時候各種產品添加了功能。僅使用MySQL和SQL-Server進行測試顯示略有不同的行爲(SQL-Server更嚴格,可能更接近規範)。這很有趣,如果其他人可以檢查其他SQL實現。 – 2011-06-12 10:24:12

5

更新的查詢:

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

它會選擇所有但從表t的最後一行。

+1

我相信這將取決於蒂姆提到的DBMS。在標準的SQL中,你必須把它寫爲'SELECT id FROM t WHERE id <(SELECT MAX(id)FROM t)' – 2011-06-11 23:46:53

+0

是的,你是對的。我只記得,從我早期的數據庫教程中,我們需要選擇前5行而不使用TOP或LIMIT或ROWNUM,這是可能的。 – Chandranshu 2011-06-11 23:49:01

+1

是的,但是然後聚合函數在子查詢的select子句中,而不是在WHERE中。我認爲子查詢不能被看作是一個聚合函數。 – n3on 2011-06-11 23:52:03

71

HAVING是等,其中以聚合函數,或者你可以使用子查詢。

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

或者

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

是的,這可以讓我知道。但是在哪裏給了。我認爲這是一個定義。 – n3on 2011-06-11 23:59:36

+0

謝謝!正是我需要知道和理解的。投票。 – Lukas 2013-09-11 22:30:48

+11

謝謝'HAVING'這個正確的答案;) – vikingsteve 2013-10-31 22:39:41

9

不能在WHERE子句中直接使用的骨料;這就是HAVING子句的用處。

您可以使用包含WHERE子句中的聚合的子查詢。

+0

我知道這是可能的子查詢,但我不知道如果那麼我可以說我可以在WHERE使用聚合函數...我認爲這是一個定義的事情。 – n3on 2011-06-12 00:01:09

+0

@ n3on:我同意......我認爲不可能直接在WHERE子句中使用聚合 - 正如我所說的那樣。只有將它們用作子查詢的一部分纔是可能的 - 在我的書中,這不會算作「在WHERE子句中」。如果你給出了這個狡猾的,細緻入微的答案,我不明白他們怎麼會讓你失望。如果這是一個多選題,那麼你更加困難。 – 2011-06-12 02:17:54

+1

查看Tim的回答。有可能的。 – 2011-06-12 10:43:18

0

另一個解決方案是移動骨料功能標量用戶定義函數

創建你的函數:

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

DECLARE @TotalAmount INT 

SET @TotalAmount = (select SUM(SaleAmount) FROM Sales where [email protected]) 

RETURN @TotalAmount 

END 

使用功能WHERE子句中

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

參考文獻:

1. 2.

希望可以幫助別人。