|
1. 关联子查询
1.1. 关联子查询和自连接在很多时候都是等价的
1.2. 使用SQL进行行间比较时,发挥主要作用的技术是关联子查询,特别是与自连接相结合的“自关联子查询”
1.3. 缺点
- 1.3.1. 代码的可读性不好
- 1.3.1.1. 特别是在计算累计值和移动平均值的例题里,与聚合一起使用后,其内部处理过程非常难理解
- 1.3.2. 性能不好
- 1.3.2.1. 特别是在SELECT子句里使用标量子查询时,性能可能会变差
2. 增长、减少、维持现状
2.1. 使用基于时间序列的表进行时间序列分析
2.2. 示例
- 2.2.1. --求与上一年营业额一样的年份(1):使用关联子查询
- SELECT year, sale
- FROM Sales S1
- WHERE sale = (SELECT sale
- FROM Sales S2
- WHERE S2.year = S1.year -1)
- ORDER BY year;
复制代码
- 2.2.2. S2.year = S1.year -1这个条件起到了将要比较的数据偏移一行的作用
- 2.2.3. --求与上一年营业额一样的年份(2):使用自连接
- SELECT S1.year, S1.sale
- FROM Sales S1,
- Sales S2
- WHERE S2.sale = S1.sale
- AND S2.year = S1.year -1
- ORDER BY year;
复制代码 3. 用列表展示与上一年的比较结果
3.1. 示例
- 3.1.1. --求出是增长了还是减少了,抑或是维持现状(1):使用关联子查询
- SELECT S1.year, S1.sale,
- CASE WHEN sale =
- (SELECT sale
- FROM Sales S2
- WHERE S2.year = S1.year -1) THEN'→'--持平
- WHEN sale >
- (SELECT sale
- FROM Sales S2
- WHERE S2.year = S1.year -1) THEN'↑'--增长
- WHEN sale <
- (SELECT sale
- FROM Sales S2
- WHERE S2.year = S1.year -1) THEN'↓'--减少
- ELSE'—'END AS var
- FROM Sales S1
- ORDER BY year;
复制代码
- 3.1.2. --求出是增长了还是减少了,抑或是维持现状(2):使用自连接查询(最早的年份不会出现在结果里)
- SELECT S1.year, S1.sale,
- CASE WHEN S1.sale = S2.sale THEN'→'
- WHEN S1.sale > S2.sale THEN'↑'
- WHEN S1.sale < S2.sale THEN'↓'
- ELSE'—'END AS var
- FROM Sales S1, Sales S2
- WHERE S2.year = S1.year -1
- ORDER BY year;
复制代码 4. 时间轴有间断时
4.1. 和过去最临近的时间进行比较
4.2. 示例
- 4.2.1. --查询与过去最临近的年份营业额相同的年份
- SELECT year, sale
- FROM Sales2 S1
- WHERE sale =
- (SELECT sale
- FROM Sales2 S2
- WHERE S2.year =
- (SELECT MAX(year) --条件2:在满足条件1的年份中,年份最早的一个
- FROM Sales2 S3
- WHERE S1.year > S3.year)) --条件1:与该年份相比是过去的年份
- ORDER BY year;
复制代码- SELECT S1.year AS year,
- S1.year AS year
- FROM Sales2 S1, Sales2 S2
- WHERE S1.sale = S2.sale
- AND S2.year = (SELECT MAX(year)
- FROM Sales2 S3
- WHERE S1.year > S3.year)
- ORDER BY year;
复制代码
- 4.2.3. --求每一年与过去最临近的年份之间的营业额之差(1):结果里不包含最早的年份
- SELECT S2.year AS pre_year,
- S1.year AS now_year,
- S2.sale AS pre_sale,
- S1.sale AS now_sale,
- S1.sale - S2.sale AS diff
- FROM Sales2 S1, Sales2 S2
- WHERE S2.year = (SELECT MAX(year)
- FROM Sales2 S3
- WHERE S1.year > S3.year)
- ORDER BY now_year;
复制代码
- 4.2.4. --求每一年与过去最临近的年份之间的营业额之差(1):结果里不包含最早的年份
- SELECT S2.year AS pre_year,
- S1.year AS now_year,
- S2.sale AS pre_sale,
- S1.sale AS now_sale,
- S1.sale - S2.sale AS diff
- FROM Sales2 S1, Sales2 S2
- WHERE S2.year = (SELECT MAX(year)
- FROM Sales2 S3
- WHERE S1.year > S3.year)
- ORDER BY now_year;
复制代码 5. 移动累计值和移动平均值
5.1. 示例
- SELECT prc_date, prc_amt,
- SUM(prc_amt) OVER (ORDER BY prc_date) AS onhand_amt
- FROM Accounts;
复制代码
- 5.1.2. 引入窗口函数的目的原本就是解决这类问题,因此这里的代码非常简洁
- 5.1.2.1. 如果选用的数据库支持窗口函数,也可以考虑使用窗口函数
- 5.1.3. 从性能方面来看,表的扫描和数据排序也都只进行了一次
- 5.1.4. --求累计值:使用冯·诺依曼型递归集合
- SELECT prc_date, A1.prc_amt,
- (SELECT SUM(prc_amt)
- FROM Accounts A2
- WHERE A1.prc_date >= A2.prc_date ) AS onhand_amt
- FROM Accounts A1
- ORDER BY prc_date;
复制代码
- 5.1.5. --求移动累计值(1):使用窗口函数
- SELECT prc_date, prc_amt,
- SUM(prc_amt) OVER (ORDER BY prc_date
- ROWS 2 PRECEDING) AS onhand_amt
- FROM Accounts;
复制代码
- 5.1.6. --求移动累计值(2):不满3行的时间区间也输出
- SELECT prc_date, A1.prc_amt,
- (SELECT SUM(prc_amt)
- FROM Accounts A2
- WHERE A1.prc_date >= A2.prc_date
- AND (SELECT COUNT(*)
- FROM Accounts A3
- WHERE A3.prc_date
- BETWEEN A2.prc_date AND A1.prc_date ) <= 3 )
- AS mvg_sum
- FROM Accounts A1
- ORDER BY prc_date;
复制代码
- 5.1.7. A3.prc_date在以A2.prc_date为起点,以A1.prc_date为终点的区间内移动
- 5.1.8. --移动累计值(3):不满3行的区间按无效处理
- SELECT prc_date, A1.prc_amt,
- (SELECT SUM(prc_amt)
- FROM Accounts A2
- WHERE A1.prc_date >= A2.prc_date
- AND (SELECT COUNT(*)
- FROM Accounts A3
- WHERE A3.prc_date
- BETWEEN A2.prc_date AND A1.prc_date ) <= 3
- HAVING COUNT(*) =3) AS mvg_sum --不满3行数据的不显示
- FROM Accounts A1
- ORDER BY prc_date;
复制代码 5.2. 基本思路是使用冯·诺依曼型递归集合
6. 查询重叠的时间区间
6.1. 示例
- SELECT reserver, start_date, end_date
- FROM Reservations R1
- WHERE EXISTS
- (SELECT *
- FROM Reservations R2
- WHERE R1.reserver <> R2.reserver --与自己以外的客人进行比较
- AND ( R1.start_date BETWEEN R2.start_date AND R2.end_date
- --条件(1):自己的入住日期在他人的住宿期间内
- OR R1.end_date BETWEEN R2.start_date AND R2.end_date));
- --条件(2):自己的离店日期在他人的住宿期间内
复制代码
- 6.1.2. --升级版:把完全包含别人的住宿期间的情况也输出
- SELECT reserver, start_date, end_date
- FROM Reservations R1
- WHERE EXISTS
- (SELECT *
- FROM Reservations R2
- WHERE R1.reserver <> R2.reserver
- AND ( ( R1.start_date BETWEEN R2.start_date
- AND R2.end_date
- OR R1.end_date BETWEEN R2.start_date
- AND R2.end_date)
- OR ( R2.start_date BETWEEN R1.start_date
- AND R1.end_date
- AND R2.end_date BETWEEN R1.start_date
- AND R1.end_date)));
复制代码 来源:https://www.cnblogs.com/lying7/p/17277869.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|