where在分組前篩選行,having在分組后篩選組。1.執行時機:where先過濾行再分組,having后過濾組;2.作用對象:where針對單行數據,having針對分組結果;3.可用列:where用原始列,having用聚合列或group by列;4.語法位置:where在group by前,having在group by后;5.性能考量:優先用where減少計算量,having用于聚合條件篩選。
簡單來說,WHERE子句在分組之前篩選行,而HAVING子句在分組之后篩選組。WHERE針對的是表中的實際數據行,HAVING針對的是GROUP BY語句分組后的結果。
WHERE和HAVING篩選條件的5大不同點
1. 執行時機:先WHERE后HAVING
這是最核心的區別。WHERE子句在數據分組之前應用,這意味著它直接作用于表中的每一行數據。想象一下,你在一個巨大的數據池里,WHERE就像一個篩子,先把不符合條件的數據行過濾掉,剩下的數據才能進入后續的分組和聚合計算。
而HAVING子句則是在數據分組和聚合之后應用。它就像是另一個篩子,但這次篩選的對象不再是原始數據行,而是GROUP BY語句產生的各個分組。只有滿足HAVING條件的分組才會被保留,其他的會被丟棄。
舉個例子,假設你有一個orders表,包含customer_id和order_amount兩列。你想找出平均訂單金額超過100的客戶。你不能直接用WHERE子句,因為WHERE只能作用于單行數據,而平均訂單金額是一個聚合值。正確的做法是先用GROUP BY按customer_id分組,然后用HAVING子句篩選平均訂單金額大于100的分組:
select customer_id, AVG(order_amount) AS avg_amount FROM orders GROUP BY customer_id HAVING AVG(order_amount) > 100;
2. 作用對象:行 vs. 組
正如上面所說,WHERE子句作用于單個數據行,它根據每一行的數據來決定是否保留該行。HAVING子句作用于由GROUP BY語句創建的分組,它根據每個分組的聚合結果來決定是否保留該分組。
3. 可用列:原始列 vs. 聚合列
WHERE子句可以使用表中的任何列,只要這些列在WHERE子句的條件表達式中是有效的。但是,WHERE子句不能使用聚合函數,比如AVG(), SUM(), MAX(), MIN(), count()。因為聚合函數是在分組之后計算的,而在WHERE子句執行的時候,分組還沒有發生。
HAVING子句則恰恰相反,它主要用于篩選聚合函數的結果。雖然HAVING子句也可以使用表中的原始列,但通常情況下,我們會用它來篩選聚合函數的結果。如果在HAVING子句中使用了原始列,那么這些列必須出現在GROUP BY子句中,否則會報錯。
4. 語法位置:WHERE在GROUP BY之前,HAVING在GROUP BY之后
sql語句的執行順序是固定的,WHERE子句必須出現在GROUP BY子句之前,而HAVING子句必須出現在GROUP BY子句之后。如果你把它們的順序搞錯了,SQL解釋器會報錯。
一個完整的SQL查詢語句的結構通常是這樣的:
SELECT column1, column2, ... FROM table_name WHERE condition GROUP BY column1, column2, ... HAVING condition ORDER BY column1, column2, ...
5. 性能考量:能用WHERE就不用HAVING
通常情況下,WHERE子句的性能比HAVING子句更好。因為WHERE子句在分組之前過濾數據,可以減少需要分組和聚合的數據量。而HAVING子句是在分組和聚合之后過濾數據,即使有很多數據行最終會被HAVING子句過濾掉,它們仍然需要先被分組和聚合,這會增加計算成本。
因此,如果你的篩選條件可以同時用WHERE子句和HAVING子句來實現,那么應該優先使用WHERE子句。比如,你想找出訂單金額大于100的客戶的平均訂單金額,你可以這樣寫:
SELECT customer_id, AVG(order_amount) AS avg_amount FROM orders WHERE order_amount > 100 GROUP BY customer_id;
而不是這樣寫:
SELECT customer_id, AVG(order_amount) AS avg_amount FROM orders GROUP BY customer_id HAVING order_amount > 100; -- 錯誤!order_amount不是聚合函數的結果,應該用WHERE
當然,如果你的篩選條件必須基于聚合函數的結果,那么就只能使用HAVING子句了。
什么時候應該使用WHERE,什么時候應該使用HAVING?
這個問題其實上面已經說了很多,但為了更清晰地總結一下,可以這樣理解:
- 使用WHERE的情況: 當你需要基于原始數據行進行篩選,并且篩選條件不涉及任何聚合函數時,使用WHERE子句。
- 使用HAVING的情況: 當你需要基于分組后的聚合結果進行篩選時,使用HAVING子句。
簡單來說,WHERE用于過濾行,HAVING用于過濾組。記住這個原則,你就不會再混淆WHERE和HAVING了。
WHERE子句中可以使用子查詢嗎?
當然可以!WHERE子句中可以使用子查詢,這是一種非常強大的SQL技巧。子查詢可以讓你在WHERE子句中使用更復雜的條件,比如根據另一個查詢的結果來篩選數據。
舉個例子,假設你有一個customers表和一個orders表,你想找出所有下過訂單的客戶。你可以使用子查詢來實現:
SELECT * FROM customers WHERE customer_id IN (SELECT customer_id FROM orders);
在這個例子中,子查詢SELECT customer_id FROM orders返回所有下過訂單的客戶的ID列表。然后,外層查詢使用WHERE customer_id IN (…)來篩選出customers表中所有ID在子查詢結果中的客戶。
子查詢還可以用于更復雜的場景,比如比較不同分組的聚合結果,或者根據動態計算的值來篩選數據。掌握子查詢的用法,可以讓你編寫更靈活和強大的SQL查詢。
HAVING子句中可以使用子查詢嗎?
和WHERE子句類似,HAVING子句也可以使用子查詢。但是,在HAVING子句中使用子查詢的情況相對較少。因為HAVING子句主要用于篩選分組后的聚合結果,而子查詢通常用于獲取原始數據。
不過,在某些特殊情況下,HAVING子句中使用子查詢也是有用的。比如,你想找出平均訂單金額高于所有客戶平均訂單金額的客戶。你可以這樣寫:
SELECT customer_id, AVG(order_amount) AS avg_amount FROM orders GROUP BY customer_id HAVING AVG(order_amount) > (SELECT AVG(order_amount) FROM orders);
在這個例子中,子查詢SELECT AVG(order_amount) FROM orders返回所有客戶的平均訂單金額。然后,HAVING子句使用AVG(order_amount) > (…)來篩選出平均訂單金額高于所有客戶平均訂單金額的客戶。
需要注意的是,在HAVING子句中使用子查詢時,要確保子查詢返回的結果是單個值,或者是一個可以與聚合函數進行比較的值。否則,SQL解釋器會報錯。