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

原文地址:https://www.cnblogs.com/evian-jeff/p/11605207.html

时间: 2024-08-29 17:31:30

SQL进阶系列之9用SQL处理数列的相关文章

SQL进阶系列之7用SQL进行集合运算

写在前面 集合论是SQL语言的根基,因为这种特性,SQL也被称为面向集合语言 导入篇:集合运算的几个注意事项 注意事项1:SQL能操作具有重复行的集合(multiset.bag),可以通过可选项ALL来支持 SQL的集合运算符提供了允许重复和不允许重复两种用法,UNION和INTERSECT结果里不会出现重复的行,UNION ALL则会保留重复行:ALL的作用和SELECT子句中的DISTINCT相反.ALL有助于优化查询性能,这是因为使用ALL后不再进行排序 注意事项2:集合运算符存在优先级

1.SQL优化系列--&gt;高手详解SQL性能优化十条经验

1.查询的模糊匹配 尽量避免在一个复杂查询里面使用 LIKE '%parm1%'—— 红色标识位置的百分号会导致相关列的索引无法使用,最好不要用. 解决办法: 其实只需要对该脚本略做改进,查询速度便会提高近百倍.改进方法如下: a.修改前台程序——把查询条件的供应商名称一栏由原来的文本输入改为下拉列表,用户模糊输入供应商名称时,直接在前台就帮忙定位到具体的供应商,这样在调用后台程序时,这列就可以直接用等于来关联了. b.直接修改后台——根据输入条件,先查出符合条件的供应商,并把相关记录保存在一个

Linq To Sql进阶系列(六)用object的动态查询与保存log篇

动态的生成sql语句,根据不同的条件构造不同的where字句,是拼接sql 字符串的好处.而Linq的推出,是为了弥补编程中的 Data != Object 的问题.我们又该如何实现用object的动态查询呢? 1,用object的查询是什么?我们可以简单的举这么一个例子.我们到公安局查找一个人.首先,我们会给出他的一些特征,比如,身高多少,年龄多少,性别,民族等.那么,我们把这个人的一些特征输入电脑.我们希望,电脑能给我们返回这个人的信息.而实际上,有相同特征的人太多了,常常返回一个集合.那让

SQL进阶系列之8EXISTS谓词的用法

写在前面 支撑SQL和关系数据库的基础理论:数学领域的集合论和逻辑学标准体系的谓词逻辑 理论篇 什么是谓词?谓词是返回值为真值(true false unknown)的函数 关系数据库里,每一个行数据可以看作是一个命题 实体的阶层 0阶实体(单行) -- 1阶谓词( = between and) 1阶实体(行集合/表) -- 2阶谓词 (exists) 2阶实体(表的集合) -- 3阶谓词 1970被毙掉,目前数据库均以二阶谓词为基准 全称量化与存在量化 全称量词:所有的\(x\)都满足条件\(

.NET深入实战系列—Linq to Sql进阶

最近在写代码的过程中用到了Linq查询,在查找资料的过程中发现网上的资料千奇百怪,于是自己整理了一些关于Linq中容易让人困惑的地方. 本文全部代码基于:UserInfo与Class两个表,其中Class中的UserId与UserInfo中的Id对应 本文唯一访问地址:http://www.cnblogs.com/yubaolee/p/BestLinqQuery.html linq联合查询 内联查询 内联是一个实际使用频率很高的查询,它查询两个表共有的且都不为空的部分 from user in

【SQL进阶】03.执行计划之旅1 - 初探

听到大牛们说执行计划,总是很惶恐,是对知识的缺乏的惶恐,所以必须得学习执行计划,以减少对这一块知识的惶恐,下面是对执行计划的第一讲-理解执行计划. 本系列[T-SQL]主要是针对T-SQL的总结. SQL基础 [T-SQL基础]01.单表查询-几道sql查询题 [T-SQL基础]02.联接查询 [T-SQL基础]03.子查询 [T-SQL基础]04.表表达式-上篇 [T-SQL基础]04.表表达式-下篇 [T-SQL基础]05.集合运算 [T-SQL基础]06.透视.逆透视.分组集 [T-SQL

SQL总结系列

SQL总结系列 总结SQL基本知识.用法,并结合多年的应用对SQL有关的相关知识进行总结.希望这些分享能给大家带来一些帮助,如有不足或错误,请批评指正. 主要内容 1)编辑相关,包括:数据库的创建与删除,表和视图的创建与修改,约束(主键.外键.唯一.默认值.校验器.非空).索引.触发器等 2)查询相关,包括基本查询.分组排序.聚合函数.连表查询(内连接.外连接.全连接.交叉连接),几乎涵盖常用查询语句 3)实战与练习,通过一些经典的题目,来挖掘如何处理处理复杂查询的办法 4)编写规范,根据经验总

转 深入浅出Mybatis系列(十)---SQL执行流程分析(源码篇)

深入浅出Mybatis系列(十)---SQL执行流程分析(源码篇) 最近太忙了,一直没时间继续更新博客,今天忙里偷闲继续我的Mybatis学习之旅.在前九篇中,介绍了mybatis的配置以及使用, 那么本篇将走进mybatis的源码,分析mybatis 的执行流程, 好啦,鄙人不喜欢口水话,还是直接上干活吧: 1. SqlSessionFactory 与 SqlSession. 通过前面的章节对于mybatis 的介绍及使用,大家都能体会到SqlSession的重要性了吧, 没错,从表面上来看,

MS SQL巡检系列&mdash;&mdash;检查外键字段是否缺少索引

前言感想:一时兴起,突然想写一个关于MS SQL的巡检系列方面的文章,因为我觉得这方面的知识分享是有价值,也是非常有意义的.一方面,很多经验不足的人,对于巡检有点茫然,不知道要从哪些方面巡检,另外一方面,网上关于MS SQL巡检方面的资料好像也不是特别多.写这个系列只是一个分享,自己的初衷是一个知识梳理.总结提炼过程,有些知识和脚本也不是原创,文章很多地方融入了自己的一些想法和见解的,不足和肤浅之处肯定也非常多,抛砖引玉,也希望大家提意见和建议.补充,指正其中的不足之处.Stay Hungry