SQL进阶系列之4HAVING字句的力量
写在前面
SQL是面向集合的语言,与面向过程和面向对象语言都不一样
寻找缺失的编号
/* 寻找缺失的编号 */
CREATE TABLE SeqTbl
(seq INTEGER PRIMARY KEY,
name VARCHAR(16) NOT NULL);
INSERT INTO SeqTbl VALUES(1, '迪克');
INSERT INTO SeqTbl VALUES(2, '安');
INSERT INTO SeqTbl VALUES(3, '莱露');
INSERT INTO SeqTbl VALUES(5, '卡');
INSERT INTO SeqTbl VALUES(6, '玛丽');
INSERT INTO SeqTbl VALUES(8, '本');
-- 如果有查询结果,说明存在缺失的编号
SELECT '存在缺失的编号' FROM SeqTbl HAVING COUNT(*) <> MAX(seq);
新的SQL标准里HAVING可以单独使用
-- 查询缺失编号的最小值,如果表包含NULL,NOT IN可能得不到正确结果
SELECT MIN(seq+1) AS gap FROM SeqTbl WHERE (seq+1) NOT IN (SELECT seq FROM SeqTbl);
用HAVING子句进行子查询:求众数
/* 用HAVING子句进行子查询:求众数(求中位数时也用本代码) */
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(*) FROM Graduates GROUP BY income HAVING COUNT(*) >= ALL(SELECT COUNT(*) FROM Graduates GROUP BY income);
-- 求众数的SQL语句(2):使用极值函数
SELECT income,count(*) FROM Graduates GROUP BY income HAVING COUNT(*) >= (SELECT MAX(cnt) FROM (SELECT COUNT(*) as cnt FROM Graduates GROUP BY income) AS tmp);
用HAVING子句进行自连接:求中位数
-- 求中位数的SQL语句:在HAVING子句中使用非等值自连接
SELECT AVG(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) AS TMP;
查询不包含NULL的集合
COUNT函数的使用方法有COUNT(*)和COUNT(<字段名>)两种,区别在于:
- COUNT(*)可以用于NULL,而COUNT(<列名>)与其他聚合函数一样,要先排除掉null再进行统计
- COUNT(*)查的是所有行的数目,而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');
-- 查询"sbmt_date"列不包含NULL的列(1):使用COUNT
SELECT dpt FROM Students GROUP BY dpt HAVING COUNT(*) = COUNT(sbmt_date);
-- 查询"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);
用关系除法进行购物篮分析
/* 用关系除法运算进行购物篮分析 */
CREATE TABLE Items
(item VARCHAR(16) PRIMARY KEY);
CREATE TABLE ShopItems
(shop VARCHAR(16),
item VARCHAR(16),
PRIMARY KEY(shop, item));
INSERT INTO Items VALUES('啤酒');
INSERT INTO Items VALUES('纸尿裤');
INSERT INTO Items VALUES('自行车');
INSERT INTO ShopItems VALUES('仙台', '啤酒');
INSERT INTO ShopItems VALUES('仙台', '纸尿裤');
INSERT INTO ShopItems VALUES('仙台', '自行车');
INSERT INTO ShopItems VALUES('仙台', '窗帘');
INSERT INTO ShopItems VALUES('东京', '啤酒');
INSERT INTO ShopItems VALUES('东京', '纸尿裤');
INSERT INTO ShopItems VALUES('东京', '自行车');
INSERT INTO ShopItems VALUES('大阪', '电视');
INSERT INTO ShopItems VALUES('大阪', '纸尿裤');
INSERT INTO ShopItems VALUES('大阪', '自行车');
-- 查到items表里商品都有的shop名称
SELECT SI.shop FROM ShopItems AS SI,Items AS I WHERE SI.item = I.item GROUP BY SI.shop
HAVING COUNT(SI.item) = (SELECT COUNT(item) FROM Items);
-- 查找全都有且只有items表中商品的shop名称
SELECT SI.shop FROM ShopItems AS SI LEFT JOIN Items AS I ON SI.item = I.item GROUP BY SI.shop HAVING COUNT(SI.item) = (SELECT COUNT(item) FROM Items) AND
COUNT(I.item) = (SELECT COUNT(item) FROM Items);
小结
- 表不是文件,记录也没有顺序,所以SQL不进行排序
- SQL不是面向过程语言,没有循环、条件分支和赋值操作
- SQL通过不断生成子集来求得目标集合
- GROUP BY子句可以用来生成子集
- WHERE子句用来调查集合元素的性质,而HAVING子句用来调查集合本身的性质
练习题
-- 1-4-1 修改编号缺失的逻辑,使结果总是返回一行数据
SELECT CASE WHEN COUNT(*) <> MAX(seq) THEN '存在缺失的编号' ELSE '不存在缺失的编号' END AS col FROM SeqTbl;
-- 1-4-2 练习"特征函数"
SELECT dpt FROM Students GROUP BY dpt HAVING COUNT(*) = SUM(CASE WHEN sbmt_date BETWEEN '2005-09-01' AND '2005-09-30' THEN 1 ELSE 0 END);
-- 1-4-3 购物篮分析问题的一般化
SELECT shop,COUNT(I.item) AS my_item_cnt,(SELECT COUNT(*) FROM Items) - COUNT(I.item) AS diff_cnt FROM ShopItems AS SI LEFT JOIN Items AS I ON SI.item = I.item GROUP BY shop;
SQL进阶系列之4HAVING字句的力量的更多相关文章
- Linq To Sql进阶系列(六)用object的动态查询与保存log篇
动态的生成sql语句,根据不同的条件构造不同的where字句,是拼接sql 字符串的好处.而Linq的推出,是为了弥补编程中的 Data != Object 的问题.我们又该如何实现用object的动 ...
- SQL进阶系列之7用SQL进行集合运算
写在前面 集合论是SQL语言的根基,因为这种特性,SQL也被称为面向集合语言 导入篇:集合运算的几个注意事项 注意事项1:SQL能操作具有重复行的集合(multiset.bag),可以通过可选项ALL ...
- SQL进阶系列之1CASE表达式
配置环境: 下载地址:https://www.enterprisedb.com/downloads/postgres-postgresql-downloads#windows 使用数据库: C:\Po ...
- SQL进阶系列之12SQL编程方法
写在前面 KISS -- keep it sweet and simple 表的设计 注意命名的意义 英文字母 + 阿拉伯数字 + 下划线"_" 属性和列 编程的方针 写注释 注意 ...
- SQL进阶系列之10HAVING子句又回来了
写在前面 HAVING子句的处理对象是集合而不是记录 各队,全队点名 --各队,全体点名! CREATE TABLE Teams (member CHAR(12) NOT NULL PRIMARY K ...
- SQL进阶系列之11让SQL飞起来
写在前面 SQL的性能优化是数据库使用者必须面对的重要问题,本节侧重SQL写法上的优化,SQL的性能同时还受到具体数据库的功能特点影响,这些不在本节讨论范围之内 使用高效的查询 参数是子查询时,使用E ...
- SQL进阶系列之9用SQL处理数列
写在前面 关系模型的数据结构里,并没有顺序的概念,但SQL处理有序集合也有坚实的理论基础 生成连续编号 --生成连续编号 CREATE TABLE Digits (digit INTEGER PRIM ...
- SQL进阶系列之8EXISTS谓词的用法
写在前面 支撑SQL和关系数据库的基础理论:数学领域的集合论和逻辑学标准体系的谓词逻辑 理论篇 什么是谓词?谓词是返回值为真值(true false unknown)的函数 关系数据库里,每一个行数据 ...
- SQL进阶系列之6用关联子查询比较行与行
写在前面 使用SQL对同一行数据进行列间的比较很简单,只需要在WHERE子句里写上比较条件就可以了,对于不同行数据进行列间比较需要使用自关联子查询. 增长.减少.维持现状 需要用到行间比较的经典场景是 ...
随机推荐
- Maya编程——沿Curve绘制圆柱
操作流程: 1. VS运行代码,生成插件 2. 打开Maya绘制曲线,加载插件 3. 选中绘制的曲线,运行插件 Posts1.0 代码: #include <maya/MSimple.h> ...
- Delphi连接Oracle控件ODAC的安装及使用
Delphi连接Oracle有很多种方式,但大多要在客户机上安装Oracle那庞大的客户端,比较不方便,使用ODAC控件连接Oracle则免去了这些麻烦.ODAC也是Oracle公司载发的控件.有fo ...
- [LeetCode] 929. Unique Email Addresses 唯一的电邮地址
Every email consists of a local name and a domain name, separated by the @ sign. For example, in ali ...
- (转) C#使用ODP.NET(Oracle.ManagedDataAccess.dll)操作Oracle数据库
原贴链接:https://www.cnblogs.com/mq0036/p/11052359.html C#使用ODP.NET(Oracle.ManagedDataAccess.dll)操作Oracl ...
- 关于Oracle报 ORA-00600: 内部错误代码, 参数: [kkqcscpopn_Int: 0], [], [], [], [], [], [], [], [], [], [], []解决
服务器上有的Oracle版本是11.2.0.1.0,但是用到了mybatis-PageHelper分页插件会报这个错误. 下面说说我是怎么遇到这个错误的:同事写的这个功能点是用到了前台分页,是正常的没 ...
- OpenLDAP + phpLDAPadmin
一.基础设置 1.1 环境说明 Centos 7.5 openldap 1.2 关闭防火墙和selinux setenforce sed -i 's/SELINUX=enforcing/SELINUX ...
- 使用 Java 移除字符串中的前导零
给定一串数字,从中删除前导零. public class Test { public static void main(String[] args) { String str = "0000 ...
- [转帖]浅谈分布式一致性与CAP/BASE/ACID理论
浅谈分布式一致性与CAP/BASE/ACID理论 https://www.cnblogs.com/zhang-qc/p/6783657.html ##转载请注明 CAP理论(98年秋提出,99年正式发 ...
- C语言return返回值深入理解
C语言使用return关键字返回函数值,可以很好对函数做封装,此处的疑问是:函数内部创建的变量都是局部变量,即私有的,作用域就在函数之内,为什么却可以把值传给调用函数? 解释这个问题还需要从C语言调用 ...
- MVC路由规则
1 可以创建多条路由规则,每条路由规则的那么属性不同 2路由规则是有顺序的.如果被前面的规则匹配了,那么后面的规则就没机会了 3 constraints 约束: 4namespaces 命名空间 5r ...