Having子句用法

时间:2019-06-12
本文章向大家介绍Having子句用法,主要包括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);

原文地址:https://www.cnblogs.com/sanzashu/p/11011227.html