「小匚学SQL」SQL速通-007-源数据的筛选及CTE

Timothy Liu

今天的课程分两块,简单介绍 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 的场景也非常多,视频仅仅是入门而已,拓展阅读:

https://www.mssqltips.com/sqlservertip/5118/sql-server-cte-vs-temp-table-vs-table-variable-performance-test/

https://docs.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql?view=sql-server-ver16


了解 小匚的个人博客 的更多信息

订阅后即可通过电子邮件收到最新文章。

了解 小匚的个人博客 的更多信息

立即订阅以继续阅读并访问完整档案。

继续阅读

了解 小匚的个人博客 的更多信息

立即订阅以继续阅读并访问完整档案。

继续阅读

退出移动版