• SQL进阶教程学习笔记


    在学习《SQL进阶教程学习》的记录笔记,现学现用效率真的很高,带着问题学习,记忆会深很多很多。


    CASE表达式有简单CASE表达式(simple caseexpression)和搜索CASE表达式(searched case expression)两种写法。

    1. --简单CASE表达式
    2. CASE sex
    3. WHEN '1' THEN ’男’
    4. WHEN '2' THEN ’女’
    5. ELSE ’其他’ END
    6. --搜索CASE表达式
    7. CASE WHEN sex ='1'THEN’男’
    8. WHEN sex ='2'THEN’女’
    9. ELSE ’其他’ END

    tips:

    1. 因为GROUP BY子句比SELECT语句先执行,所以在GROUP BY子句中引用在SELECT子句里定义的别称是不被允许的。
    • 用一条SQL语句进行不同条件的统计:

    进行不同条件的统计是CASE表达式的著名用法之一。

    • 新手用WHERE子句进行条件分支,高手用SELECT子句进行条件分支:
    1. -- 男性人口
    2. SELECT pref_name,
    3. SUM(population)
    4. FROM PopTbl2
    5. WHERE sex ='1'
    6. GROUP BY pref_name;
    7. -- 女性人口
    8. SELECT pref_name,
    9. SUM(population)
    10. FROM PopTbl2
    11. WHERE sex ='2'
    12. GROUP BY pref_name;
    1. SELECT pref_name,
    2. --男性人口
    3. SUM( CASE WHEN sex ='1'THEN population ELSE 0 END) AS cnt_m,
    4. --女性人口
    5. SUM( CASE WHEN sex ='2'THEN population ELSE 0 END) AS cnt_f
    6. FROM PopTbl2
    7. GROUP BY pref_name;
    • 用CHECK约束定义多个列的条件关系

    • 在UPDATE语句里进行条件分支
    1. --条件1
    2. UPDATE Salaries
    3. SET salary = salary * 0.9
    4. WHERE salary >= 300000;
    5. --条件2
    6. UPDATE Salaries
    7. SET salary = salary * 1.2
    8. WHERE salary >= 250000 AND salary < 280000;

    两个UPDATE函数依次执行的话,可能会反复操作同一个数据,因此会造成错误。因此使用UPDATE与CASE函数结合,而且因为只需执行一次,所以速度也更快:

    1. --用CASE表达式写正确的更新操作
    2. UPDATE Salaries
    3. SET salary = CASE WHEN salary >= 300000
    4. THEN salary * 0.9
    5. WHEN salary >= 250000 AND salary < 280000
    6. THEN salary * 1.2
    7. ELSE salary END;
    • 主键值调换:
    1. --1.将a转换为中间值d
    2. UPDATE SomeTable
    3. SET p_key ='d'
    4. WHERE p_key ='a';
    5. --2.将b调换为a
    6. UPDATE SomeTable
    7. SET p_key ='a'
    8. WHERE p_key ='b';
    9. --3.将d调换为b
    10. UPDATE SomeTable
    11. SET p_key ='b'
    12. WHERE p_key ='d';

    ​​​​​​​没有必要执行3次UPDATE操作,因此可以用UPDATE结合CASE:

    1. --用CASE表达式调换主键值
    2. UPDATE SomeTable
    3. SET p_key = CASE WHEN p_key ='a'
    4. THEN 'b'
    5. WHEN p_key ='b'
    6. THEN 'a'
    7. ELSE p_key END
    8. WHERE p_key IN ('a', 'b');
    • 表之间的数据匹配
    1. --表的匹配:使用IN谓词
    2. SELECT course_name,
    3. CASE WHEN course_id IN
    4. (SELECT course_id FROM OpenCourses
    5. WHERE month = 200706) THEN'○'
    6. ELSE'×'END AS "6月",
    7. CASE WHEN course_id IN
    8. (SELECT course_id FROM OpenCourses
    9. WHERE month = 200707) THEN'○'
    10. ELSE'×'END AS "7月",
    11. CASE WHEN course_id IN
    12. (SELECT course_id FROM OpenCourses
    13. WHERE month = 200708) THEN'○'
    14. ELSE'×'END AS "8月"
    15. FROM CourseMaster;
    16. --表的匹配:使用EXISTS谓词
    17. SELECT CM.course_name,
    18. CASE WHEN EXISTS
    19. (SELECT course_id FROM OpenCourses OC
    20. WHERE month = 200706
    21. AND OC.course_id = CM.course_id) THEN'○'
    22. ELSE'×'END AS "6月",
    23. CASE WHEN EXISTS
    24. (SELECT course_id FROM OpenCourses OC
    25. WHERE month = 200707
    26. AND OC.course_id = CM.course_id) THEN'○'
    27. ELSE'×'END AS "7月",
    28. CASE WHEN EXISTS
    29. (SELECT course_id FROM OpenCourses OC
    30. WHERE month = 200708
    31. AND OC.course_id = CM.course_id) THEN'○'
    32. ELSE'×'END AS "8月"
    33. FROM CourseMaster CM;

    tips:

    使用EXISTS时还要把两个表格的相同列表示出来。

    • 自连接
    • 排序

    方法一、使用窗口函数:

    1. --排序:使用窗口函数
    2. SELECT name, price,
    3. RANK() OVER (ORDER BY price DESC) AS rank_1,
    4. DENSE_RANK() OVER (ORDER BY price DESC) AS rank_2
    5. FROM Products;

    ​​​​​​​tips:

    1. rank_1跳过了之后的位次,rank_2没有跳过,而是连续排序。

    方法二、使用自连接:

    1. --排序从1开始。如果已出现相同位次,则跳过之后的位次
    2. SELECT P1.name,
    3. P1.price,
    4. (SELECT COUNT(P2.price)
    5. FROM Products P2
    6. WHERE P2.price > P1.price) + 1 AS rank_1
    7. FROM Products P1
    8. ORDER BY rank_1;

    ​​​​​​​

    • 三值逻辑和NULL:

    二值逻辑:true、false

    三值逻辑(three-valued logic):true、false、unknown

    两种NULL分别指的是“未知”(unknown)和“不适用”(not applicable,inapplicable)。“未知”指的是“虽然现在不知道,但加上某些条件后就可以知道”;而“不适用”指的是“无论怎么努力都无法知道”。

    三个真值之间的优先级顺序:

    1. AND的情况: false > unknown > true
    2. OR的情况: true > unknown > false

    • HAVING子句的力量:

    SQL是一种基于“面向集合”思想设计的语言,同样具备这种设计思想的语言很少;最开始学习过了某种理念的语言后,心理上会形成思维定式,从而妨碍我们理解另一种理念的语言。

    • 寻找缺失的编号
    1. -- 如果有查询结果,说明存在缺失的编号
    2. SELECT’存在缺失的编号’AS gap
    3. FROM SeqTbl
    4. HAVING COUNT(*) <> MAX(seq);

    ​​​​​​​

    如果这个查询结果有1行,说明存在缺失的编号;如果1行都没有,说明不存在缺失的编号。

    1. -- 查询缺失编号的最小值
    2. SELECT MIN(seq + 1) AS gap
    3. FROM SeqTbl
    4. WHERE (seq+ 1) NOT IN ( SELECT seq FROM SeqTbl);

    tips:

    1. HAVING子句是可以单独使用的
    • 用HAVING子句进行子查询:求众数

    众数(mode):指的是在群体中出现次数最多的值.

    1. --求众数的SQL语句(1):使用谓词
    2. SELECT income, COUNT(*) AS cnt
    3. FROM Graduates
    4. GROUP BY income
    5. HAVING COUNT(*) >= ALL ( SELECT COUNT(*)
    6. FROM Graduates
    7. GROUP BY income);
    1. --求众数的SQL语句(2):使用极值函数
    2. SELECT income, COUNT(*) AS cnt
    3. FROM Graduates
    4. GROUP BY income
    5. HAVING COUNT(*) >= ( SELECT MAX(cnt)
    6. FROM ( SELECT COUNT(*) AS cnt
    7. FROM Graduates
    8. GROUP BY income) TMP ) ;

    ​​​​​​​

    • 用HAVING子句进行自连接:求中位数

    中位数(median):指的是将集合中的元素按升序排列后恰好位于正中间的元素。

    1. --求中位数的SQL语句:在HAVING子句中使用非等值自连接
    2. SELECT AVG(DISTINCT income)
    3. FROM (SELECT T1.income
    4. FROM Graduates T1, Graduates T2
    5. GROUP BY T1.income
    6. --S1的条件
    7. HAVING SUM(CASE WHEN T2.income >= T1.income THEN 1 ELSE 0 END)
    8. >= COUNT(*) / 2
    9. --S2的条件
    10. AND SUM(CASE WHEN T2.income <= T1.income THEN 1 ELSE 0 END)
    11. >= COUNT(*) / 2 ) TMP;
    • 查询不包含NULL的集合

    COUNT函数的使用方法有COUNT(*)和COUNT(列名)两种,它们的区别有两个:

    1. 第一个是性能上的区别;
    2. 第二个是COUNT(*)可以用于NULL,而COUNT(列名)与其他聚合函数一样,要先排除掉NULL的行再进行统计。第二个区别也可以这么理解:COUNT(*)查询的是所有行的数目,而COUNT(列名)查询的则不一定是。
    1. --查询“提交日期”列内不包含NULL的学院(1):使用COUNT函数
    2. SELECT dpt
    3. FROM Students
    4. GROUP BY dpt
    5. HAVING COUNT(*) = COUNT(sbmt_date);
    1. --查询“提交日期”列内不包含NULL的学院(2):使用CASE表达式
    2. SELECT dpt
    3. FROM Students
    4. GROUP BY dpt
    5. HAVING COUNT(*) = SUM(CASE WHEN sbmt_date IS NOT NULL
    6. THEN 1
    7. ELSE 0 END);

    tips:

    1. 表不是文件,记录也没有顺序,所以SQL不进行排序。
    2. SQL不是面向过程语言,没有循环、条件分支、赋值操作。(这个思维模式真的很难改变,我的第一反应就是循环、条件分支)
    3. SQL通过不断生成子集来求得目标集合。SQL不像面向过程语言那样通过画流程图来思考问题,而是通过画集合的关系图来思考。SQL是集合语言
    •  外连接的用法:

    • ​​​​​​​EXISTS:

    • 让SQL飞起来:

    参数是子查询时,使用EXISTS代替IN

    tips:

    1. 如果IN的参数是“1, 2, 3”这样的数值列表,一般还不需要特别注意。但是如果参数是子查询,那么就需要注意了。
    2. 但是从代码的可读性上来看,IN要比EXISTS好。使用IN时的代码看起来更加一目了然,易于理解。因此,如果确信使用IN也能快速获取结果,就没有必要非得改成EXISTS了。
    3. IN的参数是子查询时,数据库首先会执行子查询,然后将结果存储在一张临时的工作表里(内联视图),然后扫描整个视图。很多情况下这种做法都非常耗费资源。使用EXISTS的话,数据库不会生成临时的工作表

    使用EXISTS时更快的原因有以下两个:

    1. 如果连接列(id)上建立了索引,那么查询Class_B时不用查实际的表,只需查索引就可以了。
    2. 如果使用EXISTS,那么只要查到一行数据满足条件就会终止查询,不用像使用IN时一样扫描全表。在这一点上NOT EXISTS也一样。

    tips:

    1. 极值函数在统计时会把为NULL的数据排除掉。

    (不定期更新。。。)

  • 相关阅读:
    02-基于DockerCompose安装Nebula Graph 3.0.0
    【OpenCV】基于opencv的视频间隔抽帧脚本
    TorchDrug教程--分子生成
    【camera】摄像头模组简单介绍
    Linu文件目录之操作篇【文件/目录的删除和创建、复制、移动、重命名】【简直不要太详细】
    Splunk的转发器扮演什么角色?
    第二章:String类
    汽车智能座舱/智能驾驶SOC -2
    【Vue】内置指令真的很常用!
    JSX基础语法
  • 原文地址:https://blog.csdn.net/weixin_41243988/article/details/134199670