SQL必知必会
陈旸
清华大学计算机博士
立即订阅
10179 人已学习
课程目录
已完结 49 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词丨SQL可能是你掌握的最有用的技能
免费
第一章:SQL语法基础篇 (19讲)
01丨了解SQL:一门半衰期很长的语言
02丨DBMS的前世今生
03丨学会用数据库的方式思考SQL是如何执行的
04丨使用DDL创建数据库&数据表时需要注意什么?
05丨检索数据:你还在SELECT * 么?
06丨数据过滤:SQL数据过滤都有哪些方法?
07丨什么是SQL函数?为什么使用SQL函数可能会带来问题?
08丨什么是SQL的聚集函数,如何利用它们汇总表的数据?
09丨子查询:子查询的种类都有哪些,如何提高子查询的性能?
10丨常用的SQL标准有哪些,在SQL92中是如何使用连接的?
11丨SQL99是如何使用连接的,与SQL92的区别是什么?
12丨视图在SQL中的作用是什么,它是怎样工作的?
13丨什么是存储过程,在实际项目中用得多么?
14丨什么是事务处理,如何使用COMMIT和ROLLBACK进行操作?
15丨初识事务隔离:隔离的级别有哪些,它们都解决了哪些异常问题?
16丨游标:当我们需要逐条处理数据时,该怎么做?
17丨如何使用Python操作MySQL?
18丨SQLAlchemy:如何使用Python ORM框架来操作MySQL?
19丨基础篇总结:如何理解查询优化、通配符以及存储过程?
第二章:SQL性能优化篇 (18讲)
20丨当我们思考数据库调优的时候,都有哪些维度可以选择?
21丨范式设计:数据表的范式有哪些,3NF指的是什么?
22丨反范式设计:3NF有什么不足,为什么有时候需要反范式设计?
23丨索引的概览:用还是不用索引,这是一个问题
24丨索引的原理:我们为什么用B+树来做索引?
25丨Hash索引的底层原理是什么?
26丨索引的使用原则:如何通过索引让SQL查询效率最大化?
27丨从数据页的角度理解B+树查询
28丨从磁盘I/O的角度理解SQL查询的成本
29丨为什么没有理想的索引?
30丨锁:悲观锁和乐观锁是什么?
31丨为什么大部分RDBMS都会支持MVCC?
32丨查询优化器是如何工作的?
33丨如何使用性能分析工具定位SQL执行慢的原因?
34丨答疑篇:关于索引以及缓冲池的一些解惑
35丨数据库主从同步的作用是什么,如何解决数据不一致问题?
36丨数据库没有备份,没有使用Binlog的情况下,如何恢复数据?
37丨SQL注入:你的SQL是如何被注入的?
第三章:认识DBMS (7讲)
38丨如何在Excel中使用SQL语言?
39丨WebSQL:如何在H5中存储一个本地数据库?
40丨SQLite:为什么微信用SQLite存储聊天记录?
41丨初识Redis:Redis为什么会这么快?
42丨如何使用Redis来实现多用户抢票问题
43丨如何使用Redis搭建玩家排行榜?
44丨DBMS篇总结和答疑:用SQLite做词云
第四章:SQL项目实战 (3讲)
45丨数据清洗:如何使用SQL对数据进行清洗?
46丨数据集成:如何对各种数据库进行集成和转换?
47丨如何利用SQL对零售数据进行分析?
结束语 (1讲)
结束语 | 互联网的下半场是数据驱动的时代
SQL必知必会
登录|注册

06丨数据过滤:SQL数据过滤都有哪些方法?

陈旸 2019-06-24
我在上篇文章中讲到过,提升查询效率的一个很重要的方式,就是约束返回结果的数量,还有一个很有效的方式,就是指定筛选条件,进行过滤。过滤可以筛选符合条件的结果,并进行返回,减少不必要的数据行。
那么在今天的内容里,我们来学习如何对 SQL 数据进行过滤,这里主要使用的就是 WHERE 子句。
你可能已经使用过 WHERE 子句,说起来 SQL 其实很简单,只要能把满足条件的内容筛选出来即可,但在实际使用过程中,不同人写出来的 WHERE 子句存在很大差别,比如执行效率的高低,有没有遇到莫名的报错等。
在今天的学习中,你重点需要掌握以下几方面的内容:
学会使用 WHERE 子句,如何使用比较运算符对字段的数值进行比较筛选;
如何使用逻辑运算符,进行多条件的过滤;
学会使用通配符对数据条件进行复杂过滤。

比较运算符

在 SQL 中,我们可以使用 WHERE 子句对条件进行筛选,在此之前,你需要了解 WHERE 子句中的比较运算符。这些比较运算符的含义你可以参见下面这张表格:
实际上你能看到,同样的含义可能会有多种表达方式,比如小于等于,可以是(<=),也可以是不大于(!>)。同样不等于,可以用(<>),也可以用(!=),它们的含义都是相同的,但这些符号的顺序都不能颠倒,比如你不能写(=<)。需要注意的是,你需要查看使用的 DBMS 是否支持,不同的 DBMS 支持的运算符可能是不同的,比如 Access 不支持(!=),不等于应该使用(<>)。在 MySQL 中,不支持(!>)(!<)等。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《SQL必知必会》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(98)

  • 一步
    就是要避免全表扫描,所以我们会考虑在 WHERE 及 ORDER BY 涉及到的列上增加索引
    -----------------------------------------------
    where 条件字段上加索引是可以明白的,但是为什么 order by 字段上还要加索引呢?这个时候已经通过 where条件过滤得到了数据,已经不需要在筛选过滤数据了,只需要在排序的时候根据字段排序就好了。不是很明白

    作者回复: 这是一个很好的问题,关于ORDER BY字段是否增加索引:
    在MySQL中,支持两种排序方式:FileSort和Index排序。Index排序的效率更高,
    Index排序:索引可以保证数据的有序性,因此不需要再进行排序。
    FileSort排序:一般在内存中进行排序,占用CPU较多。如果待排结果较大,会产生临时文件I/O到磁盘进行排序,效率较低。

    所以使用ORDER BY子句时,应该尽量使用Index排序,避免使用FileSort排序。
    当然具体优化器是否采用索引进行排序,你可以使用explain来进行执行计划的查看。
    优化建议:
    1、SQL中,可以在WHERE子句和ORDER BY子句中使用索引,目的是在WHERE子句中避免全表扫描,ORDER BY子句避免使用FileSort排序。
    当然,某些情况下全表扫描,或者FileSort排序不一定比索引慢。但总的来说,我们还是要避免,以提高查询效率。
    一般情况下,优化器会帮我们进行更好的选择,当然我们也需要建立合理的索引。
    2、尽量Using Index完成ORDER BY排序。
    如果WHERE和ORDER BY相同列就使用单索引列;如果不同使用联合索引。
    3、无法Using Index时,对FileSort方式进行调优。

    2019-06-24
    3
    37
  • Samson
    老师,似乎有个问题:“(%)和(_)的区别在于,(%)代表一个或多个字符,而(_)只代表一个字符。”

    %似乎是代表0个或任意正整数个字符,而不是一个或多个,因为如果是一个或多个的话,那么第一个例子中的太乙真人就匹配不到了。
    2019-06-24
    1
    36
  • 怪兽宇
    老师好, 平日因业务考核需要,一条查询语句查询条件需要写 30 多个 like "%A%" ,语句跑起来特别慢,请问有什么优化方法吗?

    作者回复: 可以考虑:
    1、建立索引
    2、使用函数来替代LIKE,
    如果是MySQL的话:可以考虑locate, position, instr, find_in_set
    如果是SQL Server,可以考虑charindex, patindex

    2019-06-26
    3
    15
  • 陈扬鸿
    老师,你好,现在mysql8已经没有frm文件,一旦数据字典丢失,没有表结构就无法恢复单个ibd文件的数据,如何通过mysql8的 sdi文件生成创建表的ddl语句。

    作者回复: 在MySQL8.0版本之前,当我们ALTER TABLE时系统崩溃了,则会遗留.frm,.ibd文件。而在8.0版本之后,MySQL默认的InnoDB存储引擎实现了原子DDL。原子 DDL 操作写入了内部隐藏的系统表,即mysql.innodb_ddl_log中,也就是说明在DDL执行过程中如果出现了失败,是可以回滚的。
    需要说明的是:DDL如果正常运行结束后,ddl_log中的相应日志也会被删除。如果这中间崩溃了,重启时会根据事务是否提交了来判断是做redo,还是undo DLL操作。

    2019-06-25
    14
  • 极客星星
    你好 老师 不是很明白您说的对where语句建索引是什么意思 通过sql语句怎么实现
    谢谢

    作者回复: 多谢提问,这句话我说的比较省略。想表达的意思是,如果你使用了WHERE子句,对于某个字段进行了条件筛选,那么这个字段你可以通过建立索引的方式进行SQL优化。
    因为我们在进行SQL优化的时候,应该尽量避免全表扫描。所以当我们使用WHERE子句对某个字段进行了条件筛选时,如果我们没有对这个字段建立索引,就会进入到全表扫描,因此可以考虑对这个字段建立索引。

    当然你也需要注意 索引是否会失效。因此除了考虑建立字段索引以外,你还需要考虑:
    1、不要在WHERE子句后面对字段做函数处理,同时也避免对索引字段进行数据类型转换
    2、避免在索引字段上使用<>,!=,以及对字段进行NULL判断(包括 IS NULL, IS NOT NULL)
    3、在索引字段后,慎用IN和NOT IN,如果是连续的数值,可以考虑用BETWEEN进行替换
    因为在WHERE子句中,如果对索引字段进行了函数处理,或者使用了<>,!=或NULL判断等,都会造成索引失效。

    2019-06-25
    14
  • flow
    关于通配符匹配里的 % 相当于正则表达式里的 .* 表示匹配大于等于0个任意字符,
    所以 % 太 % 匹配的是 [大于等于0个任意字符]太[大于等于0个任意字符],[东皇]太[一] 和 []太[乙真人]都符合;
    而 _% 相当于正则表达式里的 .+ 表示匹配至少一个,即大于等于1个,
    所以 '_% 太 % 匹配的是 [大于等于1个字符]太[大于等于0个字符],只有 [东皇]太[一] 符合。

    作者回复: 对的 解释正确

    2019-06-24
    2
    13
  • 悟空
    老师关于通配符给的解释,不够清晰!
    说明如下:
    SQL:SELECT name FROM heros WHERE name LIKE '_% 太 %'

    因为太乙真人的太是第一个字符,而_%太%中的太不是在第一个字符,所以匹配不到“太乙真人”,只可以匹配上“东皇太一”。

    说明:
    "_":匹配任意一个字符,包括可以匹配到“太乙真人”的太字。
    但是,整体的通配符 '_% 太 %',需要后面继续匹配到一个"太"字符,显然,"太乙真人"不符合了,如果是,"太乙真人太太",就可以匹配到。

    作者回复: 哈哈 太乙真人太太 这个解释的好。也就是在第一个字符之后能匹配上“太”字。

    2019-06-24
    10
  • 一步
    所以使用到了 DATE 函数,将字段 birthdate 转化为日期类型再进行比较
    -------------------------------------------------
    对于日期的比较,不是可以直接进行比较吗? 对于上面的例子,直接可以使用 birthdate 字段进行时间比较,为什么还要使用DATE函数转换一下呢?
    2019-06-24
    3
    7
  • stormsc
    有个问题想问老师:
    SELECT name,role_main,role_assist from heros where role_assist is not null LIMIT 5
    这样限定的查询结果为5条数据,是随机选择的5条数据吗?

    作者回复: 感谢提问,不是随机的5条。最简单的方式,你可以多重复几次,然后看下结果有没有变化。你会发现,每次运行的结果都是一样的,因此不是随机的。
    如果想实现随机5条数据,可以采用下面的方式:
    SELECT name,role_main,role_assist, RAND() as r FROM heros WHERE role_assist IS NOT NULL ORDER BY r LIMIT 5

    2019-06-25
    6
  • Jeric
    老师你好,学到目前为止课程貌似是默认大家都知道如何安装运行MYSQL,Oracle,navicat等软件。但实际作为一个初学者,我前几节课根本不知道在哪运行代码。后来自己网上找了教程安装和连接之后运行成功,不知老师是否考虑到这点,谢谢。
    2019-07-16
    1
    5
  • 看,有只猪
    解答一下对使用DATE函数的疑问:
    birthdate字段可能会有时间包含在里面,如2019-01-01 00:00:00,如果直接和2019-01-01比较是会失败的,用DATE函数可以提取出原始数据的日期部分

    作者回复: 解释的很好,关于为什么使用DATE函数的说明可以看下这个

    2019-06-25
    5
  • stormsc
    作业 mysql: select name 英雄名称, role_main 主要定位, role_assist 次要定位,hp_max 最大生命值,mp_max 最大法力值 from heros where (role_main in ('坦克','战士')
    AND role_assist is not null) AND (hp_max > 8000 or mp_max <1500) ORDER BY (hp_max+mp_max) DESC

    作者回复: 正确,同时采用了列别名的方式。

    2019-06-25
    4
  • 华夏
    SELECT name, role_main, role_assist, hp_max, mp_max
    FROM heros
    WHERE (role_main IN ('坦克', '战士') AND role_assist IS NOT NULL)
    AND (hp_max > 8000 OR mp_max < 1500)
    ORDER BY (hp_max+mp_max) DESC;
    +-----------+-----------+-------------+--------+--------+
    | name | role_main | role_assist | hp_max | mp_max |
    +-----------+-----------+-------------+--------+--------+
    | 牛魔 | 坦克 | 辅助 | 8476 | 1926 |
    | 刘邦 | 坦克 | 辅助 | 8073 | 1940 |
    | 程咬金 | 坦克 | 战士 | 8611 | 0 |
    | 张飞 | 坦克 | 辅助 | 8341 | 100 |
    | 亚瑟 | 战士 | 坦克 | 8050 | 0 |
    | 吕布 | 战士 | 坦克 | 7344 | 0 |
    | 关羽 | 战士 | 坦克 | 7107 | 10 |
    | 花木兰 | 战士 | 刺客 | 5397 | 100 |
    +-----------+-----------+-------------+--------+--------+
    8 rows in set (0.00 sec)
    2019-06-30
    1
    3
  • hlz-123
    where子句WHERE 子句中比较运算符、逻辑运算符和通配符这三者各自作用?
    1、比较运算符,比较数值的大小,数值类型可以是整数,浮点数,字符串,布尔类型等等。
    2、逻辑运算符,定义where子句中多个条件之间的关系。
    3、通配符,对文本类型字段进行模糊查询。
    Mysql查询语句:
    SELECT name,role_main,role_assist,hp_max,mp_max FROM heros
    WHERE (role_main in ('坦克','战士') AND role_assist is not null)
    AND (hp_max>8000 OR mp_max<1500) order by (hp_max+mp_max) DESC;

    作者回复: 解释的很好,最后一个SQL查询也正确

    2019-06-24
    3
  • 晓涛
    sql建立索引是什么意思,老师能详细解释下不?
    2019-08-16
    2
  • ballgod
    关于通配符的问题想问一下老师,有看过python的正则表达式,评论第三位的解释中,+是一个或无穷个,*是零个或无穷个。按照老师说的%和_的含义,_%太%应该是匹配

    作者回复: _%太% 匹配东皇太一,不会匹配到太乙真人。因为_相当于至少要匹配一个字符,所以除了第一个字符以外,需要有“太”字,也就是东皇太一。

    2019-07-13
    1
  • Amanda
    过滤上线时间 DATE(birthdate) NOT BETWEEN '2016-01-01' AND '2017-01-01',是MySQL里date类型可以直接与字符串进行比较运算?那这里birthdate可以不用 DATE 函数转换了;Oracle中日期的比较就比较严格,TO_DATE、TO_CHAR 效率也不同

    作者回复: 是的,在ORACLE中可以使用TO_CHAR, TO_DATE做转换:
    TO_CHAR 把日期或数字转换为字符串
    TO_DATE 把字符串转换为日期类型
    同时在MySQL中也有类似的函数
    DATE_FORMAT(date,'%Y-%m-%d') 对应 TO_CHAR
    STR_TO_DATE(date,'%Y-%m-%d') 对应 TO_DATE
    比如 SELECT DATE_FORMAT(NOW(),'%m-%d-%Y') AS result
    SELECT STR_TO_DATE('2017-01-01 00:10:10','%Y-%m-%d %H:%i:%s') AS result

    2019-06-27
    1
  • ꯭J꯭I꯭N꯭🙃
    SELECT name, role_main, role_assist,hp_max,mp_max
    FROM heros
    WHERE (role_main IN ('坦克','战士') AND role_assist IS NOT NULL)
    AND (hp_max > 8000 or mp_max < 1500)
    ORDER BY (hp_max+mp_max) DESC;
    2019-06-25
    1
  • Krison
    打卡,坚持学习
    2019-06-24
    1
  • MJ
    select name,role_main,role_assist,hp_max,mp_max from heros where (role_main in ('坦克','战士') and role_assist is not NULL) and (hp_max > 8000 or mp_max < 1500) order by (mp_max+hp_max) desc;

    +-----------+-----------+-------------+--------+--------+
    | name | role_main | role_assist | hp_max | mp_max |
    +-----------+-----------+-------------+--------+--------+
    | 牛魔 | 坦克 | 辅助 | 8476 | 1926 |
    | 刘邦 | 坦克 | 辅助 | 8073 | 1940 |
    | 程咬金 | 坦克 | 战士 | 8611 | 0 |
    | 张飞 | 坦克 | 辅助 | 8341 | 100 |
    | 亚瑟 | 战士 | 坦克 | 8050 | 0 |
    | 吕布 | 战士 | 坦克 | 7344 | 0 |
    | 关羽 | 战士 | 坦克 | 7107 | 10 |
    | 花木兰 | 战士 | 刺客 | 5397 | 100 |
    +-----------+-----------+-------------+--------+--------+

    作者回复: 正确,结果也显示出来了。

    2019-06-24
    1
收起评论
98
返回
顶部