「小匚学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


Discover more from 小匚的个人博客

Subscribe to get the latest posts sent to your email.

Leave a Reply

Discover more from 小匚的个人博客

Subscribe now to keep reading and get access to the full archive.

Continue reading

Discover more from 小匚的个人博客

Subscribe now to keep reading and get access to the full archive.

Continue reading