读SQL进阶教程笔记05_关联子查询

读SQL进阶教程笔记05_关联子查询

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;
  • 4.2.2.  自连接版本
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;
  • 4.2.5. 使用极值函数时会发生排序

5. 移动累计值和移动平均值

5.1. 示例

  • 5.1.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.3.1. 依赖于具体的数据库的
  • 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. 示例

  • 6.1.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

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:读SQL进阶教程笔记05_关联子查询 - Python技术站

(0)
上一篇 2023年4月17日
下一篇 2023年4月17日

相关文章

  • 配置ogg异构mysql-oracle 单向同步

    从mysql到oracle和oracle到mysql差不多。大致步骤如下: 环境是:192.168.0.165 (Mysql ) —> 192.168.0.164 ( Oracle )想将mysql的sure库下的ah6 同步到 oracle的 hr.ah6下 版本:操作系统:redhat5.8Oracle: 11.2.0.3Mysql: 5.5.37…

    MySQL 2023年4月12日
    00
  • mysql利用覆盖索引避免回表优化查询

    MySQL中的覆盖索引是指当我们查询的结果可以直接从索引中获取,而不需要再去查询数据表中其他的列时,就可以利用覆盖索引来避免回表操作,从而优化查询操作的效率,提升整个系统的性能。 以下是基本的步骤: 创建合适的索引:通过EXPLAIN命令分析查询语句,检查是否使用了索引,如果没有,则需要创建合适的索引。 包含所有必需列的索引:确保创建的索引包含所有SELEC…

    MySQL 2023年5月19日
    00
  • 解决MySQL因不能创建 PID 导致无法启动的方法

    当MySQL服务器在启动时,可能会出现因为无法创建PID文件而导致无法启动的问题。以下是解决MySQL因不能创建PID文件而无法启动的方法: 1. 检查MySQL data目录权限 首先,我们需要确保MySQL的data目录具有足够的权限来创建PID文件。可以使用以下命令检查: ls -ld /var/lib/mysql/ 如果结果类似于drwxr-xr-x…

    MySQL 2023年5月18日
    00
  • mysql常用命令以及小技巧

    下面是关于“mysql常用命令以及小技巧”的完整攻略: 1. 常用命令 1.1 连接与断开数据库 连接MySQL数据库: mysql -h host -u username -p password 注:需将 host 替换为主机名或IP地址,username 和 password 替换为数据库的用户名和密码。 退出MySQL数据库: exit; 1.2 数据…

    MySQL 2023年5月18日
    00
  • 分享下mysql各个主要版本之间的差异

    让我来向您详细讲解分享下mysql各个主要版本之间的差异的完整攻略。 1. 确定各个主要版本 首先,我们需要明确mysql的各个主要版本。常见的包括MySQL 5.5、MySQL 5.6、MySQL 5.7、MySQL 8.0等。这些版本之间有很多差异,我们需要对每个版本的新增功能、改进和移除进行了解。 2. 了解差异 接下来,我们需要了解各个主要版本之间的…

    MySQL 2023年5月19日
    00
  • Mysql常见的慢查询优化方式总结

    Mysql是一款流行的关系型数据库系统,因其高效稳定被广泛应用于各个领域。但是在实际使用过程中,由于数据量的增大,查询复杂度的提高等原因,可能会导致查询速度变慢,影响系统性能。下面将介绍几种优化Mysql慢查询的常见方式。 1. 创建索引 创建索引是提高查询效率的重要手段,可以帮助数据库快速定位到需要查询的位置。常见的索引类型有BTree索引、Hash索引、…

    MySQL 2023年5月19日
    00
  • mysql 创建root用户和普通用户及修改删除功能

    下面是 mysql 创建和管理用户的攻略: 创建 root 用户 以 root 身份登录 mysql: bash mysql -u root -p 创建新用户并授权: sql CREATE USER ‘newuser’@’localhost’ IDENTIFIED BY ‘password’; GRANT ALL PRIVILEGES ON *.* TO ‘…

    MySQL 2023年5月18日
    00
  • mysql 8.0.17 解压版安装配置方法图文教程

    下面是关于“mysql 8.0.17 解压版安装配置方法图文教程”的完整攻略: 背景说明 MySQL是一款强大的开源关系型数据库管理系统,是许多网站和应用程序背后的基石。MySQL 8.0.17是MySQL官方最新发布的稳定版本,其中的新功能和改进可以提高MySQL的性能和安全性。 步骤一:下载MySQL 8.0.17解压版 首先,我们需要从MySQL官方网…

    MySQL 2023年5月18日
    00
合作推广
合作推广
分享本页
返回顶部