目录

第一部分:基础——增删查改
【第一章】做好准备 Getting Started (时长25分钟)
【第二章】在单一表格中检索数据 Retrieving Data From a Single Table (时长53分钟)
【第三章】在多张表格中检索数据 Retrieving Data From Multiple Tables (时长1小时2分)
【第四章】插入、更新和删除数据 Inserting, Updating, and Deleting Data (时长42分钟)

第二部分:基础进阶——汇总、复杂查询、内置函数
【第五章】汇总数据 Summarizing Data (时长33分钟)
【第六章】编写复杂查询 Writing Complex Query (时长45分钟)
【第七章】MySQL的基本函数 Essential MySQL Functions (时长33分钟)

第三部分:提高效率——视图、存储过程、函数
【第八章】视图 Views (时长18分钟)
【第九章】存储过程 Stored Procedures (时长48分钟)

第四部分:高阶主题——触发器、事件、事务、并发
【第十章】触发器和事件 Triggers and Events (时长22分钟)
【十一章】事务和并发 Transactions and Concurrency (时长49分钟)

第五部分:脱颖而出——数据类型、设计数据库、索引、保护
【十二章】数据类型 Data Types (时长35分钟)
【十三章】设计数据库 Designing Databases (时长1时30分)
【十四章】高效的索引 Indexing for High Performance (时长58分钟)
【十五章】保护数据库 Securing Databases (时长20分钟)

【第一章】做好准备

什么是SQL

  • 关系型非关系型两类数据库,在更流行的关系型数据库中,我们把数据存储在通过某些关系相互关联的数据表中,每张表储存特定的一类数据,这正是关系型数据库名称的由来。(如:顾客表通过顾客id与订单表相联系,订单表又通过商品id与商品表相联系)
  • SQL(Structured Query Language,结构化查询语言)是专门用来处理(包括查询和修改)关系型数据库的标准语言
  • 不同关系型数据库管理系统语法(MySQL、SQL Server、Oracle)略有不同,但都是基于标准SQL,本课使用最流行的开源关系型数据库管理系统,MySQL

【第二章】在单一表格中检索数据

选择子句

  • SELECT 是列/字段选择语句,可选择列,列间数学表达式,特定值或文本,可用AS关键字设置列别名(AS可省略),注意 DISTINCT 关键字的使用。

  • SQL会完全无视大小写(绝大数情况下的大小写)、多余的空格(超过一个的空格)、缩进和换行,SQL语句间完全由分号 ; 分割

  • 单价涨价10%作为新单价 :

SELECT
name,
unit_price,
unit_price * 1.1 ‘new price’
FROM products
如上面这个例子所示,取别名时,AS 可省,空格后跟别名就行,可看作是SQL会将将列变量及其数学运算之后的第一个空格识别为AS

WHERE子句

  • WHERE 是行筛选条件,实际是一行一行/一条条记录依次验证是否符合条件,进行筛选
  • 实例

USE sql_store;

SELECT *
FROM customers
WHERE points > 3000
/WHERE state != ‘va’ – ‘VA’/'va’一样

  • 比较运算符中注意等于是一个等号而不是两个等号
  • 也可对日期或文本进行比较运算,注意SQL里日期的标准写法及其需要用引号包裹这一点
    WHERE birth_date > ‘1990-01-01’

AND, OR, NOT运算符

USE sql_store;

SELECT *
FROM customers
WHERE birth_date > ‘1990-01-01’ AND points > 1000
/WHERE birth_date > ‘1990-01-01’ OR
points > 1000 AND state = ‘VA’

  • AND优先级高于OR,但最好加括号,更清晰
  • NOT的用法 :

WHERE NOT (birth_date > ‘1990-01-01’ OR points > 1000)

IN运算符

IN运算符将某一属性与多个值(一系列值)进行比较
实质是多重相等比较运算条件的简化

案例

选出’va’、‘fl’、'ga’三个州的顾客

USE sql_store;

SELECT * FROM customers
WHERE state = ‘va’ OR state = ‘fl’ OR state = ‘ga’

  • 用 IN 操作符简化该条件
    WHERE state IN (‘va’, ‘fl’, ‘ga’)
  • 可加NOT
    WHERE state NOT IN (‘va’, ‘fl’, ‘ga’)
  • 库存量刚好为49、38或72的产品 :

USE sql_store;

select * from products
where quantity_in_stock in (49, 38, 72)

BETWEEN运算符

用于表达范围型条件

用AND而非括号
闭区间,包含两端点
也可用于日期,毕竟日期本质也是数值,日期也有大小(早晚),可比较运算

  • 选出积分在1k到3k的顾客 :

USE sql_store;

select * from customers
where points >= 1000 and points <= 3000
等效简化为:

WHERE points BETWEEN 1000 AND 3000
注意两端都是包含的 不能写作BETWEEN (1000, 3000)!别和IN的写法搞混

  • 选出90后的顾客 :

SELECT * FROM customers
WHERE birth_date BETWEEN ‘1990-01-01’ AND ‘2000-01-01’

LIKE运算符

模糊查找,查找具有某种模式的字符串的记录/行

过时用法(但有时还是比较好用,之后发现好像用的还是比较多的),下节课的正则表达式更灵活更强大
注意和正则表达式一样都是用引号包裹表示字符串
USE sql_store;
SELECT * FROM customers
WHERE last_name like ‘brush%’ / ‘b____y’
引号内描述想要的字符串模式,注意SQL(几乎)任何情况都是不区分大小写的

两种通配符:

% 任何个数(包括0个)的字符(用的更多)
_ 单个字符

  • 分别选择满足如下条件的顾客:
  1. 地址包含 ‘TRAIL’ 或 ‘AVENUE’

  2. 电话号码以 9 结束

USE sql_store;

select *
from customers
where address like ‘%Trail%’ or
address like ‘%avenue%’
LIKE 执行优先级在逻辑运算符之后,毕竟 IN BETWEEN LIKE 本质可看作是比较运算符的简化,应该和比较运算同级,数学→比较→逻辑,始终记住这个顺序,上面这个如果用正则表达式会简单得多

where phone like ‘%9’
/where phone not like ‘%9’
LIKE的判断结果也是个TRUE/FASLE的问题,任何逻辑值/布林值都可前置NOT来取反

REGEXP运算符

正则表达式,在搜索字符串方面更为强大,可搜索更复杂的模板

实例

USE sql_store;

select * from customers
where last_name like ‘%field%’
等效于:

where last_name regexp ‘field’
regexp 是 regular expression(正则表达式) 的缩写

正则表达式可以组合来表达更复杂的字符串模式

where last_name regexp ‘^mac|field$|rose’
where last_name regexp ‘[gi]e|e[fmq]’ – 查找含ge/ie或ef/em/eq的
where last_name regexp ‘[a-h]e|e[c-j]’

正则表达式总结:

符号 意义
^ 开头
$ 结尾
[abc] 含abc
[a-c] 含a到c
| logical or
(正则表达式用法还有更多,自己去查)

练习

分别选择满足如下条件的顾客:

  1. first names 是 ELKA 或 AMBUR

  2. last names 以 EY 或 ON 结束

  3. last names 以 MY 开头 或包含 SE

  4. last names 包含 BR 或 BU

select *
from customers
where first_name regexp ‘elka|ambur’
/where last_name regexp ‘ey∣on|on∣on’
/where last_name regexp ‘^my|se’
/where last_name regexp ‘b[ru]’/‘br|bu’

IS NULL运算符

找出空值,找出有某些属性缺失的记录

  • 找出电话号码缺失的顾客,也许发个邮件提醒他们之类

USE sql_store;

select * from customers
where phone is null/is not null
注意是 IS NULL 和 IS NOT NULL 这里 NOT 不是前置于布林值,而是更符合英语语法地放在了be动词后

  • 找出还没发货的订单(在线商城管理员的常见查询需求)

USE sql_store;

select * from orders
where shipper_id is null

  • 回顾 :

3~9 节全在讲WHERE子句中条件的具体写法 :

第3节:比较运算 > < = >= <= !=
第4节:逻辑运算 AND、OR、NOT
5~9节:特殊的比较运算(是否符合某种条件):IN 和 BETWEEN、LIKE 和 REGEXP、IS NULL
所以总的来说WHERE条件就是

数学运算 → 比较运算(包括特殊的比较运算)→ 逻辑运算
逻辑层次和执行优先级也是按照这三个的顺序来的。

ORDER BY子句

排序语句,和 SELECT …… 很像:

可多列
可以是列间的数学表达式
可包括任何列,包括没选择的列(MySQL特性,其它DBMS可能报错),
可以是之前定义好的别名列(MySQL特性,甚至可以是用一个常数设置的列别名)
任何一个排序依据列后面都可选加 DESC
注意

最好别用 ORDER BY 1, 2(表示以 SELECT …… 选中列中的第1、2列为排序依据) 这种隐性依据,因为SELECT选择的列一变就容易出错,还是显性地写出列名作为排序依据比较好

注:workbench 中扳手图标可打开表格的设计模式,查看或修改表中各列(属性),可以看到谁是主键。省略排序语句的话会默认按主键排序

  • 实例 :

USE sql_store;

select name, unit_price * 1.1 + 10 as new_price
from products
order by new_price desc, product_id
– 这两个分别是 别名列 和 未选择列,都用到了 MySQL 特性

  • 订单2的商品按总价降序排列 :

法1. 可以以总价的数学表达式为排序依据

select * from order_items
where order_id = 2
order by quantity * unit_price desc
– 列间数学表达式
法2. 或先定义总价别名,在以别名为排序依据

select *, quantity * unit_price as total_price
from order_items
where order_id = 2
order by total_price desc
– 列别名

LIMIT子句

限制返回结果的记录数量,“前N个” 或 “跳过M个后的前N个”

  • 实例

USE sql_store;

select * from customers
limit 3 / 300 / 6, 3
6, 3 表示跳过前6个,取第7~9个,6是偏移量,
如:网页分页 每3条记录显示一页 第3页应该显示的记录就是 limit 6, 3

  • 找出积分排名前三的死忠粉

USE sql_store;

select *
from customers
order by points desc
limit 3

  • 回顾

SELECT 语句完结了,里面的子句顺序固定要记牢,顺序乱会报错
select from where + order by limit
纵选列,确定表,横选行(各种条件写法和组合要清楚熟悉),最后再进行排序和限制

【第三章】在多张表格中检索数据

内连接

  • 各表分开存放是为了减少重复信息和方便修改,需要时可以根据相互之间的关系连接成相应的合并详情表以满足相应的查询。FROM JOIN ON 语句就是告诉sql: 将哪几张表以什么基础连接/合并起来。
  • 这种有多表合并的查询语句可分两部分从后往前看:
  1. 后面的 from 表A join 表B on AB的关系,就是以某些相关联的列为依据(关系型数据库就是这么来的)进行多表合并得到所需的详情表
  2. 前面的 select 就是在合并详情表中找到所需的列
  • 关于表别名 :之前在SELECT中给选定的列加别名主要是为了得到更有意义的列名,这里在 FROM JOIN 中给表加别名主要是为了简化
USE sql_store;select order_id, o.customer_id, first_name, last_name
from orders as o    -- 这里as也是可省略的
(inner) join customers c on o.customer_id = c.customer_id  -- join默认是inner join
  • 因为别名需要在 WHERE JOIN 语句中确定等原因,最好先SELECT * FROM 选择全部,等写好了 FROM JOIN ON 等后面的语句,即确定了选哪些表以及怎么链接它们并取好了表别名后,再回头去 SELECT 里细化明确需要的列。

跨数据库连接(合并)

  • 有时需要选取不同库的表的列,其他都一样,就只是WHERE JOIN里对于非现在正在用的库的表要加上库名前缀而已。依然可用别名来简化
  • 可见只有非当前使用的库才要加库前缀
use sql_store;select * from order_items oi
join sql_inventory.products pon oi.product_id = p.product_id

自连接

  • 一个表和它自己合并。如下面的例子,员工的上级也是员工,所以也在员工表里,所以想得到的有员工和他的上级信息的合并表,就要员工表自己和自己合并,用两个不同的表别名即可实现。这个例子中只有两级,但也可用类似的方法构建多层级的组织结构。
  • 自合并必然每列都要加表前缀,因为每列都同时在两张表中出现。另外,两个 first_name 列有歧义,注意将最后一列改名为 manager 使得结果表更易于理解
USE sql_hr;select e.employee_id,e.first_name,m.first_name as manager
from employees e
join employees mon e.reports_to = m.employee_id

多表连接

  • FROM 一个核心表A,用多个 JOIN …… ON …… 分别通过不同的链接关系链接不同的表B、C、D……,通常是让表B、C、D……为表A提供更详细的信息从而合并为一张详情合并版A表。将得到一个合并了BCD……等表详细信息的详情合并版A表。真实工作场景中有时甚至要合并十多张表
FROM  A JOIN B ON AB的关系 JOIN C ON AC的关系 JOIN D ON AD的关系
  • 订单表同时链接顾客表和订单状态表,合并为有顾客和状态信息的详细订单表
USE sql_store;SELECT o.order_id, o.order_date,c.first_name,c.last_name,os.name AS status
FROM orders o
JOIN customers cON o.customer_id = c.customer_id
JOIN order_statuses osON o.status = os.order_status_id
  • 同理,支付记录表链接顾客表和支付方式表形成支付记录详情表
USE sql_invoicing;SELECT p.invoice_id,p.date,p.amount,c.name,pm.name AS payment_method
FROM payments p
JOIN clients cON p.client_id = c.client_id
JOIN payment_methods pmON p.payment_method = pm.payment_method_id

复合连接条件

  • 像订单项目(order_items)这种表,订单id和产品id合在一起才能唯一表示一条记录,这叫复合主键,设计模式下也可以看到两个字段都有PK标识,订单项目备注表(order_item_notes)也是这两个复合主键,因此他们两合并时要用复合条件:FROM 表1 JOIN 表2 ON 条件1 【AND】 条件2
  • 将订单项目表和订单项目备注表合并
USE sql_store;SELECT *
FROM order_items oi
JOIN order_item_notes oinON oi.order_Id = oin.order_IdAND oi.product_id = oin.product_id

隐式连接语法

  • 就是用FROM WHERE取代FROM JOIN ON
  • 尽量别用,因为若忘记WHERE条件筛选语句,不会报错但会得到交叉合并(cross join)结果:即10条order会分别与10个customer结合,得到100条记录。最好使用显性合并语法,因为会强制要求你写合并条件ON语句,不至于漏掉。
  • 合并顾客表和订单表,显性合并:
USE sql_store;SELECT *
FROM orders o
JOIN customers cON o.customer_id = c.customer_id
  • 隐式合并语法:
SELECT *
FROM orders o, customers c
WHERE o.customer_id = c.customer_id
  • 注意 FROM 子句里的逗号,就像 SELECT 多条列用逗号隔开一样,FROM 多个表也用逗号隔开,此时若忘记WHERE条件筛选语句则得到这几张表的交叉合并结果
  • 这里也可以看得出来,ON/USING 和 WHERE 以及后面会学的 HAVING 的作用是类似的,本质上都是对行进行筛选的条件语句,只不过使用的位置不一样而已

外连接

  • (INNER) JOIN 结果只包含两表的交集,另外注意“广播(broadcast)”效应
  • LEFT/RIGHT (OUTER) JOIN 结果里除了交集,还包含只出现在左/右表中的记录
  • 合并顾客表和订单表,用 INNER JOIN:
USE sql_store;SELECT c.customer_id,c.first_name,o.order_id
FROM customers c
JOIN orders oON o.customer_id = c.customer_id
ORDER BY customer_id
  • 这样是INNER JOIN,只展示有订单的顾客(及其订单),也就是两张表的交集,但注意这里因为一个顾客可能有多个订单,所以INNER JOIN以后顾客信息其实是是广播了的,即一条顾客信息被多条订单记录共用,当然 这叫广播(broadcast)效应,是另一个问题,这里关注的重点是 INNER JOIN 的结果确实是两表的交集,是那些同时有顾客信息和订单信息的记录。
  • 若要展示全部顾客(及其订单,如果有的话),要改用LEFT (OUTER) JOIN,结果相较于 INNER JOIN 多了没有订单的那些顾客,即只有顾客信息没有订单信息的记录
  • 当然,也可以调换左右表的顺序(即调换FROM和JOIN的对象)再 RIGHT JOIN,即:
FROM orders oRIGHT [OUTER] JOIN customers c-- 中括号 [] 表示是可选项、可省略 ON o.customer_id = c.customer_id
  • 若要展示全部订单(及其顾客),就应该是 orders RIGHT JOIN customers,结果相较于 INNER JOIN 多了没有顾客的那些订单,即只有订单信息没有顾客信息的记录。(注:因为这里所有订单都有顾客,所以这里 RIGHT JOIN 结果和 INNER JOIN 一样
  • 展示各产品在订单项目中出现的记录和销量,也要包括没有订单的产品
SELECT p.product_id,p.name, -- 或者直接nameoi.quantity -- 或者直接quantity
FROM products p
LEFT JOIN order_items oiON p.product_id = oi.product_id

多表外连接

  • 与内连接类似,我们可以对多个表(3个及以上)进行外连接,最好只用 JOIN 和 LEFT JOIN
  • 查询顾客、订单和发货商记录,要包括所有顾客(包括无订单的顾客),也要包括所有订单(包括未发出的)
USE sql_store;SELECT c.customer_id,c.first_name,o.order_id,sh.name AS shipper
FROM customers c
LEFT JOIN orders oON c.customer_id = o.customer_id
LEFT JOIN shippers shON o.shipper_id = sh.shipper_id
ORDER BY customer_id
  • 最佳实践 :虽然可以调换顺序并用 RIGHT JOIN,但作为最佳实践,最好调整顺序并统一只用 [INNER] JOIN 和 LEFT [OUTER] JOIN(总是左表全包含),这样,当要合并的表比较多时才方便书写和理解而不易混乱
  • 查询 订单 + 顾客 + 发货商 + 订单状态,包括所有的订单(包括未发货的),其实就只是前两个优先级变了一下,是要看全部订单而非全部顾客了

SQL进阶教程 | 史上最易懂SQL教程 5小时零基础成长SQL大师相关推荐

  1. SQL进阶教程 | 史上最易懂SQL教程 5小时零基础成长SQL大师(3)

    [第八章]视图 创建视图 就是创建虚拟表,自动化一些重复性的查询模块,简化各种复杂操作(包括复杂的子查询和连接等) 注意视图虽然可以像一张表一样进行各种操作,但并没有真正储存数据,数据仍然储存在原始表 ...

  2. SQL进阶教程 | 史上最易懂SQL教程!10小时零基础成长SQL大师!!

    文章目录 介绍 chapter1-选择语句 选择子句 exercise where子句 exercise and or 和not运算符 exercise in运算符 exercise BETWEEN运 ...

  3. SQL进阶教程 | 史上最易懂SQL教程 5小时零基础成长SQL大师(5)

    [十二章]数据类型 介绍 MySQL的数据分为以下几个大类: String Types 字符串类型 Numeric Types 数字类型 Date and Time Types 日期和时间类型 Blo ...

  4. SQL进阶教程 | 史上最易懂SQL教程 5小时零基础成长SQL大师(4)

    [第十章]触发器和事件 触发器 触发器是在插入.更新或删除语句前后自动执行的一段SQL代码(A block of SQL code that automatically gets executed b ...

  5. 史上最简单MySQL教程详解(进阶篇)之存储过程(一)

    史上最简单MySQL教程详解(进阶篇)之存储过程(一) 史上最简单MySQL教程详解(进阶篇)之存储过程(一) 什么是存储过程 存储过程的作用 如何使用存储过程 创建存储过程 DELIMITER改变分 ...

  6. 史上最简单MySQL教程详解(进阶篇)之存储引擎介绍及默认引擎设置

    什么是存储引擎? MySQL存储引擎种类 MyISAM 引擎 InnoDB引擎 存储引擎操作 查看存储引擎 存储引擎的变更 修改默认引擎 什么是存储引擎? 与其他数据库例如Oracle 和SQL Se ...

  7. 史上最简单MySQL教程详解(进阶篇)之视图

    史上最简单MySQL教程详解(进阶篇)之视图 为什么要用视图 视图的本质 视图的作用 如何使用视图 创建视图 修改视图 删除视图 查看视图 使用视图检索 变更视图数据 WITH CHECK OPTIO ...

  8. mysql查球队胜场和败场sql_NBA 史上实力最弱的球队是哪个?用 Python + SQL 我们找到了答案...

    原标题:NBA 史上实力最弱的球队是哪个?用 Python + SQL 我们找到了答案 雷锋网按:此前我们专门发布了一篇文章分析NBA史上实力最强的球队,详见<用 Python 分析过去四年的比 ...

  9. 史上最简单MySQL教程详解(进阶篇)之索引及失效场合总结

    史上最简单MySQL教程详解(进阶篇)之索引及其失效场合总结 什么是索引及其作用 索引的种类 各存储引擎对于索引的支持 简单介绍索引的实现 索引的设置与分析 普通索引 唯一索引(Unique Inde ...

最新文章

  1. 使用Apache Commons Configuration读取配置信息
  2. MySQL 5.6 Warning - Using a password on the command line interface can be insecur 解决方案
  3. vs2010 将.mc编译为.rc文件
  4. 最简单的视音频播放示例7:SDL2播放RGB/YUV
  5. 黄章diss小米9:贱人贱己贱行业 之后秒删
  6. C++类继承内部类实例
  7. Anacodna 环境迁移详解
  8. Linux基础知识点
  9. 指向类对象的指针非空但是部分对象成员不存在原因分析
  10. 代号斗罗显示服务器暂未开放,代号斗罗手游
  11. 函数判断的和是用android,WPJAM Basic 内置的系统和设备判断函数
  12. python3+selenium实现126邮箱登陆并发送带附件的邮件(显示等待版本)
  13. php 随机几率,php 随机概率程序算法
  14. http 503 service
  15. 第115章 属性关键字 - SqlListDelimiter
  16. 了解一下winsock
  17. 一文讲透支付宝沙箱的基本应用
  18. centos7/redhat7创建私有云(owncloud)
  19. Python打印输出的方法
  20. 计算机网络-详解DNS域名解析全过程

热门文章

  1. 数据库表-权限表应用
  2. ALV中下拉列表列的实现
  3. java 调用 wsdl形式的webservice 示例
  4. 7、Power Map—实例:添加二维数据表以及批注
  5. 2K17能力值上90的11位球员,你怎么看?
  6. 天合公司 TRW Inc.
  7. 会计记忆总结之一:总论
  8. SAP 外向交货的包装功能实现
  9. SAP读取财务报表版本的标准函数
  10. SAP HANA:开启企业管理软件下一波革新浪潮?