Having子句用法


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);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM