1-6 用关联子查询比较行与行
增长、减少、维持现状
-- 求与上一年营业额一样的年份(1):使用关联子查询
SELECT
year,
sale
FROM Sales S1
WHERE sale=(SELECT sale
FROM Sales S2
WHERE S2.year=S1.year - 1)
ORDER BY year;
用列表展示与上一年的比较结果
-- 求出是增长了还是减少了,抑或是维持现状(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;
--
-- 求出是增长了还是减少了,抑或是维持现状(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;
~可以当个参考。
时间轴有间断时:和过去最临近的时间进行比较**
-- 查询与过去最临近的年份营业额相同的年份:同时使用自连接
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;
-- 求每一年与过去最临近的年份之间的营业额之差(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.saleAS diff
FROM Sales2 S1, Sales2 S2
WHERE S2.year=(SELECT MAX(year)
FROM Sales2 S3
WHERE S1.year > S3.year)
ORDER BY now_year;
-- 求每一年与过去最临近的年份之间的营业额之差(2):使用自外连接。结果里包含最早的年份**
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
LEFT OUTER JOIN Sales2 S2
ON S2.year=(SELECT MAX(year)
FROM Sales2 S3
WHERE S1.year > S3.year)
ORDER BY now_year;
~理解起来容易,要自己写出来就有点难度了。
移动累计值和移动平均值**
-- Accounts(处理日期#prc_date,处理金额#prc_amt)
-- 求累计值:使用冯· 诺依曼型递归集合
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;
-- 求移动累计值(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;
--
-- 移动累计值(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;
--
-- 去掉聚合并输出
SELECT
A1.prc_date AS A1_date,
A2.prc_date AS A2_date,
A2.prc_amt AS amt
FROM Accounts A1,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
ORDER BY A1_date, A2_date;
-- Reservations(入住客人#reserver,入住日期#start_date,离店日期#end_date)
-- 求重叠的住宿期间
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):自己的离店日期在他人的住宿期间内
-- 升级版:把完全包含别人的住宿期间的情况也输出
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)));