Having基礎用法
集合結果指定條件
注:HAVING子句中能夠使用三種要素:常數,聚合函數,GROUP BY子句中指定的列名(聚合建)
HAVING子句:
用having就一定要和group by連用, 用group by不一有having(它只是一個篩選條件用的)
商品品種分組后結果中篩選出數據行數為2行的數據:
SELECT product_type, COUNT(*)
FROM Product
GROUP BY product_type
HAVING COUNT(*) = 2;
平均數,銷售價格大於2500的
SELECT product_type, AVG(sale_price)
FROM Product
GROUP BY product_type
HAVING AVG(sale_price) >= 2500;
相對於HAVING子句,更適合寫再Where子句中的條件:
- where子句 = 指定行所對應的條件
- having子句 = 指定組所對應的條件
聚合建所對應的條件不應該書寫在HAVING子句中,而應書寫在WHERE子句當中。雖執行結果一樣,但將條件寫在where子句中比寫在having子句中的處理速度更快,返回結果時間更短。
原因:聚合操作時,DBMS內部會進行排序處理,where在排序之前就對數據進行過濾,having是在排序之后在對數據進行分組。
-- 先過濾后分組
SELECT product_type, COUNT(*)
FROM Product
GROUP BY product_type
HAVING product_type = '衣服';
-- 先分組后過濾(性能差點)
SELECT product_type, COUNT(*)
FROM Product
WHERE product_type = '衣服'
GROUP BY product_type;
尋找缺失編號
| seq | name |
|---|---|
| 1 | 小明 |
| 2 | 小紅 |
| 3 | 小王 |
| 5 | 小李 |
| 6 | 小黃 |
| 8 | 小小 |
-- 查看是否存在缺失編號
SELECT '存在缺失的編號' AS gap
FROM SeqTbl
HAVING COUNT(*) <> MAX(seq);
-- 查詢缺失編號的最小值
SELECT MIN(seq + 1) AS ga
FROM SeqTbl
WHERE (seq+ 1) NOT IN ( SELECT seq FROM SeqTbl)
如果表 SeqTbl 里包含 NULL ,那么這條 SQL 語句的查詢結果就不正確了(因為null值表示不確定)
用 HAVING 子句進行子查詢:求眾數
平均值有一個缺點,那就是很容易受到離群值(outlier)的影響。這種時候就必須使用更能准確反映出群體趨勢的指標——眾數(mode)就是其中之一。它指的是在群體中出現次數最多的值
CREATE TABLE Graduates
(name VARCHAR(16) PRIMARY KEY,
income INTEGER NOT NULL);
-- 桑普森是個離群值,會拉高平均數
INSERT INTO Graduates VALUES('桑普森', 400000);
INSERT INTO Graduates VALUES('邁克', 30000);
INSERT INTO Graduates VALUES('懷特', 20000);
INSERT INTO Graduates VALUES('阿諾德', 20000);
INSERT INTO Graduates VALUES('史密斯', 20000);
INSERT INTO Graduates VALUES('勞倫斯', 15000);
INSERT INTO Graduates VALUES('哈德遜', 15000);
INSERT INTO Graduates VALUES('肯特', 10000);
INSERT INTO Graduates VALUES('貝克', 10000);
INSERT INTO Graduates VALUES('斯科特', 10000);
-- 眾數的SQL 語句(1):使用謂詞
SELECT income, COUNT(*) AS cnt
FROM Graduates
GROUP BY income HAVING COUNT(*) >= ALL ( SELECT COUNT(*) FROM Graduates GROUP BY income)
ALL 謂詞用於 NULL 或空集時會出現問題,可以用極值函數來代替
-- 求眾數的SQL 語句(2) :使用極值函數
SELECT income, COUNT(*) AS cnt
FROM Graduates
GROUP BY incomeHAVING COUNT(*) >= ( SELECT MAX(cnt)
FROM ( SELECT COUNT(*) AS cnt
FROM Graduates
GROUP BY income) TMP )
用 HAVING 子句進行自連接:求中位數
中位數:統計學中的專有名詞,代表一個樣本、種群或概率分布中的一個數值,其可將數值集合划分為相等的上下兩部分。
-- 將集合里的元素按照大小分為上半部分和下半部分兩個子集,同時讓這 2 個子集共同擁有集合正中間的元素
SELECT T1.income FROM Graduates T1, Graduates T2 GROUP BY T1.income
HAVING SUM(CASE WHEN T2.income >= T1.income THEN 1 ELSE 0 END) >= COUNT(*) / 2
AND SUM(CASE WHEN T2.income <= T1.income THEN 1 ELSE 0 END) >= COUNT(*) / 2
-- 將上下部分集合平均然后得中值
SELECT AVG(DISTINCT income) FROM (
SELECT T1.income FROM Graduates T1, Graduates T2 GROUP BY T1.income
HAVING SUM(CASE WHEN T2.income >= T1.income THEN 1 ELSE 0 END) >= COUNT(*) / 2
AND SUM(CASE WHEN T2.income <= T1.income THEN 1 ELSE 0 END) >= COUNT(*) / 2 ) TMP;
查詢不包含 NULL 的集合
COUNT()和COUNT(列)的區別:
第一個是性能上的區別;
第二個是 COUNT()可以用於NULL,而COUNT(列名)與其他聚合函數一樣,要先排除掉NULL 的行再進行統計。
CREATE TABLE Students
(student_id INTEGER PRIMARY KEY,
dpt VARCHAR(16) NOT NULL,
sbmt_date DATE);
INSERT INTO Students VALUES(100, '理學院', '2005-10-10');
INSERT INTO Students VALUES(101, '理學院', '2005-09-22');
INSERT INTO Students VALUES(102, '文學院', NULL);
INSERT INTO Students VALUES(103, '文學院', '2005-09-10');
INSERT INTO Students VALUES(200, '文學院', '2005-09-22');
INSERT INTO Students VALUES(201, '工學院', NULL);
INSERT INTO Students VALUES(202, '經濟學院', '2005-09-25');
-- 查詢“提交日期”列內不包含NULL 的學院(1) :使用COUNT 函數
SELECT dpt
FROM Students
GROUP BY dpt
HAVING COUNT(*) = COUNT(sbmt_date);
-- 查詢“提交日期”列內不包含NULL 的學院(2) :使用CASE 表達式
SELECT dpt
FROM Students
GROUP BY dpt
HAVING COUNT(*) = SUM(CASE WHEN sbmt_date IS NOT NULL THEN 1 ELSE 0 END);
