
今天的课程分两块,简单介绍 WHERE 字句,以及 CTE 表达式。
WHERE
WHERE 后面跟的是 针对数据源的筛选条件—— search_condition。
这个条件的结果通常都是 是否 问题。由数据库替我们把记录和筛选条件一条条地对照,得到 「是」 的结果。
注意条件判断的 等号 就是一个单等号。有一次考试的时候写 SQL,最后几分钟全改错了,全改成 == 了。
1 需求:选出 FirstName 和 老师一样的人
SELECT * FROM Person.Person
WHERE FirstName = ‘Timothy’
针对每一条数据进行过滤,是等于的话就这样搞。
2 需求:选出 Initial Name 是 TL 的人
(1)Initial:SUBSTRING(1,1)需要先创建出来
SELECT FirstName + ‘ ’ + LastName As FullName, SUBSTRING(FirstName, 1, 1) + SUBSTRING(LastName, 1, 1) AS Initial
FROM Person.Person
还有一个内置函数:CONCAT 可以拼接任意多个
SELECT CONCAT(FirstName, ‘ ’, LastName) As FullName, CONCAT(SUBSTRING(FirstName, 1, 1), SUBSTRING(LastName, 1, 1)) AS Initial
FROM Person.Person
推荐使用 CONCAT,还会帮忙检验语法。
(2)下一步,要针对 Initial 进行选择,直接用 WHERE 是不行的,WHERE 筛选的只能是 数据源 中的列,不能是按摩出来的(聚合函数、内置函数加工得到的新列):
SELECT CONCAT(FirstName, ‘ ’, LastName) As FullName, CONCAT(SUBSTRING(FirstName, 1, 1), SUBSTRING(LastName, 1, 1)) AS Initial FROM Person.Person -- WHERE Initial = 'TL' 是不合法的,WHERE语句只能筛选 数据源
解决办法:
法一:
SELECT CONCAT(FirstName, ' ', LastName) AS FullName,
CONCAT(SUBSTRING(FirstName, 1, 1), SUBSTRING(LastName, 1, 1)) AS Initial
FROM Person.Perso
WHERE CONCAT(SUBSTRING(FirstName, 1, 1), SUBSTRING(LastName, 1, 1)) = 'TL';
WHERE 后面再计算一下,这样用到的还是数据源,但是很致命的:
重复是罪恶之源。
客户改了需求怎么办,只改了选择的时候的结果,筛选没有改,就容易出错。
法二:
嵌套查询——SELECT 的数据源可以是另一个 SELECT 查询的结果。
封装成数据源,起表名。
SELECT * FROM (SELECT CONCAT(FirstName, ‘ ’, LastName) As FullName, CONCAT(SUBSTRING(FirstName, 1, 1), SUBSTRING(LastName, 1, 1)) AS Initial
FROM Person.Person) AS PersonName
WHERE Initial = 'TL'-- 这样是 ok 的。
用到了嵌套的子查询,嵌套的很深。如果内层的还要有其他数据源呢?难懂也难改。
3 CTE (Common Table Expression) 提前表达出来,后面直接使用:
WITH PersonName AS
(SELECT CONCAT(FirstName, ‘ ’, LastName) As FullName,
CONCAT(SUBSTRING(FirstName, 1, 1), SUBSTRING(LastName, 1, 1)) AS Initial
FROM Person.Person)
SELECT * FROM
PersonName
WHERE Initial = 'TL'
那这个和视图不是很像吗,在网上看到说 CTE 的一个优点就是没有创建视图权限的人又想达到类似效果,就可以用 CTE。
万物皆可拆
把拆出来的子查询摘出来,放到前面。把层层套娃,拆出来。不违反筛选从数据源中来的原则。
说来,我学了就很想用。很巧的是,男朋友是一个后端开发,给我看了一句他写的一长串 SQL,非常得意地说这个是他想了很久的 SQL 给写好了。用到了 两张 SELECT FROM INNER JOIN 的结果。于是我果断建议他,写成 WITH,好懂一些。
但其实我犯了一个错,我认为 CTE 一定要效率高,而且没有去看文档。
文档中也有怎么在一个 SQL 查询中 用两个 CTE 表达式,只需要一个 WITH 就可以了。我认为学了一个工具,那它一定非常好用,而且是效能上也很好(而且脑子里还认为是老师讲的,其重新看了一遍发现老师也没说啊哈哈)。但仔细查看文档后,发现性能优化还是要取决于应用场景和数据库查询索引等配置。
在男朋友的场景下,他跑了几次的结果相差并不大。
而 CTE 最大的优化点是:
多次关联同一个结果集的场景,以及结果集绕过 SELECT WHERE 的限制。
并且 CTE 的场景也非常多,视频仅仅是入门而已,拓展阅读:

