在学习《SQL进阶教程学习》的记录笔记,现学现用效率真的很高,带着问题学习,记忆会深很多很多。
-
CASE表达式
CASE表达式有简单CASE表达式(simple caseexpression)和搜索CASE表达式(searched case expression)两种写法。
--简单CASE表达式CASE sexWHEN '1' THEN ’男’WHEN '2' THEN ’女’ELSE ’其他’ END--搜索CASE表达式CASE WHEN sex ='1'THEN’男’WHEN sex ='2'THEN’女’ELSE ’其他’ END
tips:
- 因为GROUP BY子句比SELECT语句先执行,所以在GROUP BY子句中引用在SELECT子句里定义的别称是不被允许的。
- 用一条SQL语句进行不同条件的统计:
进行不同条件的统计是CASE表达式的著名用法之一。
- 新手用WHERE子句进行条件分支,高手用SELECT子句进行条件分支:
-- 男性人口SELECT pref_name,SUM(population)FROM PopTbl2WHERE sex ='1'GROUP BY pref_name;-- 女性人口SELECT pref_name,SUM(population)FROM PopTbl2WHERE sex ='2'GROUP BY pref_name;
SELECT pref_name,--男性人口SUM( CASE WHEN sex ='1'THEN population ELSE 0 END) AS cnt_m,--女性人口SUM( CASE WHEN sex ='2'THEN population ELSE 0 END) AS cnt_fFROM PopTbl2GROUP BY pref_name;
- 用CHECK约束定义多个列的条件关系
- 在UPDATE语句里进行条件分支
--条件1UPDATE SalariesSET salary = salary * 0.9WHERE salary >= 300000;--条件2UPDATE SalariesSET salary = salary * 1.2WHERE salary >= 250000 AND salary < 280000;
两个UPDATE函数依次执行的话,可能会反复操作同一个数据,因此会造成错误。因此使用UPDATE与CASE函数结合,而且因为只需执行一次,所以速度也更快:
--用CASE表达式写正确的更新操作UPDATE SalariesSET salary = CASE WHEN salary >= 300000THEN salary * 0.9WHEN salary >= 250000 AND salary < 280000THEN salary * 1.2ELSE salary END;
-
主键值调换:
--1.将a转换为中间值dUPDATE SomeTableSET p_key ='d'WHERE p_key ='a';--2.将b调换为aUPDATE SomeTableSET p_key ='a'WHERE p_key ='b';--3.将d调换为bUPDATE SomeTableSET p_key ='b'WHERE p_key ='d';
没有必要执行3次UPDATE操作,因此可以用UPDATE结合CASE:
--用CASE表达式调换主键值UPDATE SomeTableSET p_key = CASE WHEN p_key ='a'THEN 'b'WHEN p_key ='b'THEN 'a'ELSE p_key ENDWHERE p_key IN ('a', 'b');
- 表之间的数据匹配
--表的匹配:使用IN谓词SELECT course_name,CASE WHEN course_id IN(SELECT course_id FROM OpenCoursesWHERE month = 200706) THEN'○'ELSE'×'END AS "6月",CASE WHEN course_id IN(SELECT course_id FROM OpenCoursesWHERE month = 200707) THEN'○'ELSE'×'END AS "7月",CASE WHEN course_id IN(SELECT course_id FROM OpenCoursesWHERE month = 200708) THEN'○'ELSE'×'END AS "8月"FROM CourseMaster;--表的匹配:使用EXISTS谓词SELECT CM.course_name,CASE WHEN EXISTS(SELECT course_id FROM OpenCourses OCWHERE month = 200706AND OC.course_id = CM.course_id) THEN'○'ELSE'×'END AS "6月",CASE WHEN EXISTS(SELECT course_id FROM OpenCourses OCWHERE month = 200707AND OC.course_id = CM.course_id) THEN'○'ELSE'×'END AS "7月",CASE WHEN EXISTS(SELECT course_id FROM OpenCourses OCWHERE month = 200708AND OC.course_id = CM.course_id) THEN'○'ELSE'×'END AS "8月"FROM CourseMaster CM;
tips:
使用EXISTS时还要把两个表格的相同列表示出来。
-
自连接
- 排序
方法一、使用窗口函数:
--排序:使用窗口函数SELECT name, price,RANK() OVER (ORDER BY price DESC) AS rank_1,DENSE_RANK() OVER (ORDER BY price DESC) AS rank_2FROM Products;
tips:
- rank_1跳过了之后的位次,rank_2没有跳过,而是连续排序。
方法二、使用自连接:
--排序从1开始。如果已出现相同位次,则跳过之后的位次SELECT P1.name,P1.price,(SELECT COUNT(P2.price)FROM Products P2WHERE P2.price > P1.price) + 1 AS rank_1FROM Products P1ORDER BY rank_1;
-
三值逻辑和NULL:
二值逻辑:true、false
三值逻辑(three-valued logic):true、false、unknown
两种NULL分别指的是“未知”(unknown)和“不适用”(not applicable,inapplicable)。“未知”指的是“虽然现在不知道,但加上某些条件后就可以知道”;而“不适用”指的是“无论怎么努力都无法知道”。
三个真值之间的优先级顺序:
- AND的情况: false > unknown > true
- OR的情况: true > unknown > false
-
HAVING子句的力量:
SQL是一种基于“面向集合”思想设计的语言,同样具备这种设计思想的语言很少;最开始学习过了某种理念的语言后,心理上会形成思维定式,从而妨碍我们理解另一种理念的语言。
- 寻找缺失的编号
-
EXISTS
-
让SQL飞起来:
参数是子查询时,使用EXISTS代替IN
tips:
- 如果IN的参数是“1, 2, 3”这样的数值列表,一般还不需要特别注意。但是如果参数是子查询,那么就需要注意了。
- 但是从代码的可读性上来看,IN要比EXISTS好。使用IN时的代码看起来更加一目了然,易于理解。因此,如果确信使用IN也能快速获取结果,就没有必要非得改成EXISTS了。
- 当IN的参数是子查询时,数据库首先会执行子查询,然后将结果存储在一张临时的工作表里(内联视图),然后扫描整个视图。很多情况下这种做法都非常耗费资源。使用EXISTS的话,数据库不会生成临时的工作表。
使用EXISTS时更快的原因有以下两个:
- 如果连接列(id)上建立了索引,那么查询Class_B时不用查实际的表,只需查索引就可以了。
- 如果使用EXISTS,那么只要查到一行数据满足条件就会终止查询,不用像使用IN时一样扫描全表。在这一点上NOT EXISTS也一样。
tips:
- 极值函数在统计时会把为NULL的数据排除掉。
(不定期更新。。。)