SQL进阶系列之9用SQL处理数列
写在前面
关系模型的数据结构里,并没有顺序的概念,但SQL处理有序集合也有坚实的理论基础
生成连续编号
--生成连续编号
CREATE TABLE Digits
(digit INTEGER PRIMARY KEY);
INSERT INTO Digits VALUES (0);
INSERT INTO Digits VALUES (1);
INSERT INTO Digits VALUES (2);
INSERT INTO Digits VALUES (3);
INSERT INTO Digits VALUES (4);
INSERT INTO Digits VALUES (5);
INSERT INTO Digits VALUES (6);
INSERT INTO Digits VALUES (7);
INSERT INTO Digits VALUES (8);
INSERT INTO Digits VALUES (9);
-- 创建00-99的序列
SELECT (D1.digit + D2.digit * 10) AS seq
FROM Digits AS D1 CROSS JOIN Digits AS D2
ORDER BY seq;
-- 创建1到542的序列
SELECT (D1.digit + D2.digit * 10 + D3.digit * 100) AS seq
FROM Digits AS D1,Digits AS D2,Digits AS D3
WHERE (D1.digit + D2.digit * 10 + D3.digit * 100) BETWEEN 1 AND 542
ORDER BY seq;
CREATE VIEW Sequence (seq) AS
SELECT D1.digit + (D2.digit * 10 ) + (D3.digit * 100)
FROM Digits D1,Digits D2,Digits D3;
SELECT seq FROM Sequence WHERE seq BETWEEN 1 AND 100 ORDER BY seq;
求全部的缺失编号
-- EXCEPT版
SELECT seq FROM Sequence WHERE seq BETWEEN 1 AND 12
EXCEPT (SELECT * FROM SeqTbl);
-- NOT IN版
SELECT seq FROM Sequence WHERE seq BETWEEN 1 AND 12 AND seq
NOT IN (SELECT * FROM SeqTbl);
-- 动态地指定连续编号范围的SQL语句
SELECT seq FROM Sequence WHERE seq BETWEEN (SELECT MIN(seq) FROM SeqTbl) AND (SELECT MAX(seq) FROM SeqTbl) EXCEPT (SELECT * FROM SeqTbl);
三个人能坐得下吗?
--三个人能坐得下吗?
CREATE TABLE Seats
( seat INTEGER NOT NULL PRIMARY KEY,
status CHAR(6) NOT NULL
CHECK (status IN ('未预订', '已预订')) );
INSERT INTO Seats VALUES (1, '已预订');
INSERT INTO Seats VALUES (2, '已预订');
INSERT INTO Seats VALUES (3, '未预订');
INSERT INTO Seats VALUES (4, '未预订');
INSERT INTO Seats VALUES (5, '未预订');
INSERT INTO Seats VALUES (6, '已预订');
INSERT INTO Seats VALUES (7, '未预订');
INSERT INTO Seats VALUES (8, '未预订');
INSERT INTO Seats VALUES (9, '未预订');
INSERT INTO Seats VALUES (10, '未预订');
INSERT INTO Seats VALUES (11, '未预订');
INSERT INTO Seats VALUES (12, '已预订');
INSERT INTO Seats VALUES (13, '已预订');
INSERT INTO Seats VALUES (14, '未预订');
INSERT INTO Seats VALUES (15, '未预订');
-- 找出需要的空位(1):不考虑座位的换排
SELECT S1.seat AS start_seat,'~',S2.seat AS end_seat
FROM Seats S1,Seats S2
WHERE S2.seat = S1.seat + 2 AND NOT EXISTS
(SELECT * FROM Seats S3 WHERE S3.seat BETWEEN S1.seat AND S2.seat AND S3.status <> '未预订');
--考虑座位的折返
CREATE TABLE Seats2
( seat INTEGER NOT NULL PRIMARY KEY,
row_id CHAR(1) NOT NULL,
status CHAR(6) NOT NULL
CHECK (status IN ('未预订', '已预订')) );
INSERT INTO Seats2 VALUES (1, 'A', '已预订');
INSERT INTO Seats2 VALUES (2, 'A', '已预订');
INSERT INTO Seats2 VALUES (3, 'A', '未预订');
INSERT INTO Seats2 VALUES (4, 'A', '未预订');
INSERT INTO Seats2 VALUES (5, 'A', '未预订');
INSERT INTO Seats2 VALUES (6, 'B', '已预订');
INSERT INTO Seats2 VALUES (7, 'B', '已预订');
INSERT INTO Seats2 VALUES (8, 'B', '未预订');
INSERT INTO Seats2 VALUES (9, 'B', '未预订');
INSERT INTO Seats2 VALUES (10,'B', '未预订');
INSERT INTO Seats2 VALUES (11,'C', '未预订');
INSERT INTO Seats2 VALUES (12,'C', '未预订');
INSERT INTO Seats2 VALUES (13,'C', '未预订');
INSERT INTO Seats2 VALUES (14,'C', '已预订');
INSERT INTO Seats2 VALUES (15,'C', '未预订');
-- 找出需要的空位(2):考虑座位的换排
SELECT S1.seat AS start_seat,'~',S2.seat AS end_seat
FROM Seats2 S1,Seats2 S2
WHERE S2.seat = S1.seat + 2 AND NOT EXISTS
(SELECT * FROM Seats2 S3 WHERE S3.seat BETWEEN S1.seat AND S2.seat AND (S3.status <> '未预订' OR S3.row_id <> S1.row_id));
最多能坐下多少人
--最多能坐下多少人?
CREATE TABLE Seats3
( seat INTEGER NOT NULL PRIMARY KEY,
status CHAR(6) NOT NULL
CHECK (status IN ('未预订', '已预订')) );
INSERT INTO Seats3 VALUES (1, '已预订');
INSERT INTO Seats3 VALUES (2, '未预订');
INSERT INTO Seats3 VALUES (3, '未预订');
INSERT INTO Seats3 VALUES (4, '未预订');
INSERT INTO Seats3 VALUES (5, '未预订');
INSERT INTO Seats3 VALUES (6, '已预订');
INSERT INTO Seats3 VALUES (7, '未预订');
INSERT INTO Seats3 VALUES (8, '已预订');
INSERT INTO Seats3 VALUES (9, '未预订');
INSERT INTO Seats3 VALUES (10, '未预订');
-- 先生成存储了所有序列的视图
CREATE VIEW Sequences(start_seat,end_seat,seat_cnt) AS
SELECT S1.seat AS start_seat,S2.seat AS end_seat,S2.seat-S1.seat + 1 AS seat_cnt
FROM Seats3 S1,Seats3 S2
WHERE S1.seat < S2.seat
AND NOT EXISTS (SELECT * FROM Seats3 S3 WHERE (S3.seat BETWEEN S1.seat AND S2.seat AND S3.status<> '未预订') OR (S3.seat = S2.seat + 1 AND S3.status = '未预订') OR (S3.seat = S1.seat - 1 AND S3.status = '未预订'));
-- 取出最长的序列
SELECT start_seat,end_seat,seat_cnt FROM
Sequences WHERE seat_cnt = (SELECT MAX(seat_cnt) FROM Sequences);
单调递增和单调递减
--单调递增和单调递减
CREATE TABLE MyStock
(deal_date DATE PRIMARY KEY,
price INTEGER );
INSERT INTO MyStock VALUES ('2007-01-06', 1000);
INSERT INTO MyStock VALUES ('2007-01-08', 1050);
INSERT INTO MyStock VALUES ('2007-01-09', 1050);
INSERT INTO MyStock VALUES ('2007-01-12', 900);
INSERT INTO MyStock VALUES ('2007-01-13', 880);
INSERT INTO MyStock VALUES ('2007-01-14', 870);
INSERT INTO MyStock VALUES ('2007-01-16', 920);
INSERT INTO MyStock VALUES ('2007-01-17', 1000);
-- 生成起点到终点的组合
SELECT My1.deal_date,My2.deal_date
FROM MyStock AS My1,MyStock AS My2
WHERE My1.deal_date < My2.deal_date
AND NOT EXISTS
(SELECT * FROM MyStock AS My3,MyStock AS My4
WHERE My3.deal_date BETWEEN My1.deal_date AND My2.deal_date
AND My3.deal_date BETWEEN My1.deal_date AND My2.deal_date
AND My3.deal_date < My4.deal_date
AND My3.price >= My4.price);
--排除掉子集,只取最长的时间区间
SELECT MIN(start_date) AS start_date, /* 最大限度地向前延伸起点 */
end_date
FROM (SELECT S1.deal_date AS start_date,
MAX(S2.deal_date) AS end_date /* 最大限度地向后延伸终点 */
FROM MyStock S1, MyStock S2
WHERE S1.deal_date < S2.deal_date
AND NOT EXISTS
(SELECT *
FROM MyStock S3, MyStock S4
WHERE S3.deal_date BETWEEN S1.deal_date AND S2.deal_date
AND S4.deal_date BETWEEN S1.deal_date AND S2.deal_date
AND S3.deal_date < S4.deal_date
AND S3.price >= S4.price)
GROUP BY S1.deal_date) TMP
GROUP BY end_date
ORDER BY start_date;
小结
- SQL处理数据的方法有两种
- 第一种把数据看成忽略了顺序的集合
- 第二种把数据看成有序的集合,此时的基本方法如下:
- 首先自连接生成起点到终点的集合
- 其次在子查询中描述内部的各个元素之间必须满足的关系
- 要在SQL中表达全称量化时,需要将全称量化命题转化为存在量化命题的否定形式,并使用NOT EXISTS谓词。
练习题
/* 练习题1-9-1:求所有的缺失编号——NOT EXISTS和外连接
NOT EXISTS版 */
SELECT seq
FROM Sequence N
WHERE seq BETWEEN 1 AND 12
AND NOT EXISTS
(SELECT *
FROM SeqTbl S
WHERE N.seq = S.seq );
/* 练习题1-9-1:求所有的缺失编号——NOT EXISTS和外连接
NOT EXISTS版 */
SELECT N.seq
FROM Sequence N LEFT OUTER JOIN SeqTbl S
ON N.seq = S.seq
WHERE N.seq BETWEEN 1 AND 12
AND S.seq IS NULL;
/* 练习题1-9-2:求序列——面向集合的思想 */
SELECT S1.seat AS start_seat, '~' , S2.seat AS end_seat
FROM Seats S1, Seats S2, Seats S3
WHERE S2.seat = S1.seat + (:head_cnt -1)
AND S3.seat BETWEEN S1.seat AND S2.seat
GROUP BY S1.seat, S2.seat
HAVING COUNT(*) = SUM(CASE WHEN S3.status = '未预订' THEN 1 ELSE 0 END);
/* 坐位有换排时 */
SELECT S1.seat AS start_seat, ' ~ ' , S2.seat AS end_seat
FROM Seats2 S1, Seats2 S2, Seats2 S3
WHERE S2.seat = S1.seat + (:head_cnt -1)
AND S3.seat BETWEEN S1.seat AND S2.seat
GROUP BY S1.seat, S2.seat
HAVING COUNT(*) = SUM(CASE WHEN S3.status = '未预订'
AND S3.row_id = S1.row_id THEN 1 ELSE 0 END);
/* 练习题1-9-3:求所有的序列——面向集合的思想 */
SELECT S1.seat AS start_seat,
S2.seat AS end_seat,
S2.seat - S1.seat + 1 AS seat_cnt
FROM Seats3 S1, Seats3 S2, Seats3 S3
WHERE S1.seat <= S2.seat /* 第一步:生成起点和终点的组合 */
AND S3.seat BETWEEN S1.seat - 1 AND S2.seat + 1
GROUP BY S1.seat, S2.seat
HAVING COUNT(*) = SUM(CASE WHEN S3.seat BETWEEN S1.seat AND S2.seat
AND S3.status = '未预订' THEN 1 /* 条件1 */
WHEN S3.seat = S2.seat + 1 AND S3.status = '已预订' THEN 1 /* 条件2 */
WHEN S3.seat = S1.seat - 1 AND S3.status = '已预订' THEN 1 /* 条件3 */
ELSE 0 END);
SQL进阶系列之9用SQL处理数列的更多相关文章
- SQL进阶系列之11让SQL飞起来
写在前面 SQL的性能优化是数据库使用者必须面对的重要问题,本节侧重SQL写法上的优化,SQL的性能同时还受到具体数据库的功能特点影响,这些不在本节讨论范围之内 使用高效的查询 参数是子查询时,使用E ...
- SQL进阶系列之7用SQL进行集合运算
写在前面 集合论是SQL语言的根基,因为这种特性,SQL也被称为面向集合语言 导入篇:集合运算的几个注意事项 注意事项1:SQL能操作具有重复行的集合(multiset.bag),可以通过可选项ALL ...
- [SQL SERVER系列]读书笔记之SQL注入漏洞和SQL调优
最近读了程序员的SQL金典这本书,觉得里面的SQL注入漏洞和SQL调优总结得不错,下面简单讨论下SQL注入漏洞和SQL调优. 1. SQL注入漏洞 由于“'1'='1'”这个表达式永远返回 true, ...
- Linq To Sql进阶系列(六)用object的动态查询与保存log篇
动态的生成sql语句,根据不同的条件构造不同的where字句,是拼接sql 字符串的好处.而Linq的推出,是为了弥补编程中的 Data != Object 的问题.我们又该如何实现用object的动 ...
- SQL进阶系列之12SQL编程方法
写在前面 KISS -- keep it sweet and simple 表的设计 注意命名的意义 英文字母 + 阿拉伯数字 + 下划线"_" 属性和列 编程的方针 写注释 注意 ...
- SQL进阶系列之10HAVING子句又回来了
写在前面 HAVING子句的处理对象是集合而不是记录 各队,全队点名 --各队,全体点名! CREATE TABLE Teams (member CHAR(12) NOT NULL PRIMARY K ...
- SQL进阶系列之8EXISTS谓词的用法
写在前面 支撑SQL和关系数据库的基础理论:数学领域的集合论和逻辑学标准体系的谓词逻辑 理论篇 什么是谓词?谓词是返回值为真值(true false unknown)的函数 关系数据库里,每一个行数据 ...
- SQL进阶系列之6用关联子查询比较行与行
写在前面 使用SQL对同一行数据进行列间的比较很简单,只需要在WHERE子句里写上比较条件就可以了,对于不同行数据进行列间比较需要使用自关联子查询. 增长.减少.维持现状 需要用到行间比较的经典场景是 ...
- SQL进阶系列之5外连接的用法
写在前面 SQL本身是作为一种数据提取工具而出现,使用SQL生成各种定制化报表和非定制化报表并非SQL原本用途的功能,但这并不意味着SQL无法实现这些功能. 用外连接进行行列转换(1)(行 → 列): ...
随机推荐
- Parcel 搭建浏览器自动刷新的 非 SPA项目
重点:parcel index.html 需要引入 index.js 否则不自动刷新
- setup_function和teardown_function
setup_function和teardown_function 所有用例开始和所有用例结束只调用一次
- [K8s] Kubernetes 是什么 不是什么
现在有三种部署方式,传统物理机部署.虚拟机部署.容器化部署. 我们现在所使用的云上服务器一般都是虚拟化出来的,硬件资源独立,操作系统等软件资源亦独立. 容器化的好处是更轻量,复用下层的操作系统,相当于 ...
- 【MongoDB学习之二】MongoDB数据库、文档、集合、元数据
环境 MongoDB 4.0 CentOS6.5_x64 一.连接语法格式: mongodb://[username:password@]host1[:port1][,host2[:port2],.. ...
- php删除目录及目录下的内容
今天遇到一个问题: java写的API,ppt转图片生成的目录和文件 在使用php调用API完成后,再使用php进行删除时,遇到了删除失败的问题 部署的环境是Ubuntu 导致删除失败的原因是权限的问 ...
- SQL Server表分区(转)
什么是表分区 一般情况下,我们建立数据库表时,表数据都存放在一个文件里. 但是如果是分区表的话,表数据就会按照你指定的规则分放到不同的文件里,把一个大的数据文件拆分为多个小文件,还可以把这些小文件放在 ...
- sync 简单实现 父子组件的双向绑定
这里主要是对vue文档中的sync进行一个再解释: 如果自己尝试的话,最好在已经使用emit 和prop实现了双向绑定的组件中尝试,以免出现不必要的错误: <!DOCTYPE html> ...
- 【windows】win10局域网共享文件夹
1.打开 2.共享文件夹 另一台局域网电脑可根据共享的电脑ip访问就可以了[格式:\\ip] 如果右键文件夹没有共享选项
- linux CC攻击解决方法
linux CC攻击1 由于不断的请求接口 导致带宽不足 然后不断的运行mysql语句 造成cpu饱和 这个时候服务器重负不堪 导致运行代码暖慢 导致入侵 一般采取的方法http://newmirac ...
- 在ensp上的动态NAT的配置
原理 实验模拟 搭建实验拓扑 相关参数 配置静态NAT ,一对一映射 首先设置静态路由,使路由器能够访问 我们ping一下抓一下包 发现我们出去的包已经封装成为了另外一个ip 配置动态NAT ,一对一 ...