读书:SQL必知必会

第 1 课 了解 SQL

知识点:
1.数据库(database):保存有组织的数据的容器(通常是一个文件或一组文件)

2.注意:人们通常用数据库这个术语来代表他们使用的数据库软件,这是不正
确的,也因此产生了许多混淆。
确切地说,数据库软件应称为数据库管理系统(DBMS)。数据库是通过 DBMS 创建和操纵的容器,而具体它究竟是什么,形式如何,各种数据库都不一样。

3.表(table):某种特定类型数据的结构化清单

4.表名:使表名成为唯一的,实际上是数据库名和表名等的组合。
有的数据库还使用数据库拥有者的名字作为唯一名的一部分。
也就是说,虽然在相同数据库中不能两次使用相同的表名,但在不同的数据库中完全可以使用相同的表名

5.模式:描述表的这组信息就是所谓的模式(schema),模式可以用来描述数据库中特定的表,也可以用来描述整个数据库(和其中表的关系)。

6.列(column):表中的一个字段。所有表都是由一个或多个列组成的。

7.数据类型:数据库中每个列都有相应的数据类型。
数据类型(datatype)定义了列可以存储哪些数据种类。
例如,如果列中存储的是数字(或许是订单中的物品数),则相应的数据类型应该为数值类型。如果列中存储的是日期、文本、注释、金额等,则应该规定好恰当的数据类型。

8.行(row):表中的一个记录(也可以说是数据库记录(record))

9.主键(primary key):一列(或一组列),其值能够唯一标识表中每一行

10.什么是 SQL——SQL(发音为字母 S-Q-L 或 sequel)是 Structured Query Language(结构化查询语言)的缩写。SQL 是一种专门用来与数据库沟通的语言。
目的:提供一种从数据库中读写数据的简单有效的方法

第 2 课 检索数据

2.1 SELECT 语句

1.检索单个列

SELECT prod_name FROM Products; 

注意:多条 SQL 语句必须以分号(;)分隔,
SQL 语句不区分大小写,因此 SELECT 与 select 是相同的
在处理 SQL 语句时,其中所有空格都被忽略。

三种写法相同
SELECT prod_name
FROM Products;

SELECT prod_name FROM Products;

SELECT
prod_name
FROM
Products; 

2.检索多个列

SELECT prod_id, prod_name, prod_price
FROM Products; 

3.检索所有列

SELECT *
FROM Products; 

使用通配符
一般而言,除非你确实需要表中的每一列,否则最好别使用*通配符。
虽然使用通配符能让你自己省事,不用明确列出所需列,但检索不需
要的列通常会降低检索和应用程序的性能

检索未知列
使用通配符有一个大优点。由于不明确指定列名(因为星号检索每一
列),所以能检索出名字未知的列

4.检索不同的值:DISTINCT 关键字,它指示数据库只返回不同的值

不能部分使用 DISTINCT
DISTINCT 关键字作用于所有的列,不仅仅是跟在其后的那一列。例
如,你指定 SELECT DISTINCT vend_id, prod_price,除非指定的
两列完全相同,否则所有的行都会被检索出来。

5.限制结果:TOP 关键字来限制最多返回多少行

SELECT TOP 5 prod_name
FROM Products; 前五条数据

每种数据库的限制有所不同,我这里在学习mysql
限制;使用 MySQL、MariaDB、PostgreSQL 或者 SQLite,需要使用 LIMIT子句

SELECT prod_name
FROM Products
LIMIT 5 OFFSET 5; 

以我的为例,我的数据:
在这里插入图片描述

SELECT * FROM task_tasks ORDER BY taskid LIMIT 5,1
limit  X,Y  中X表示跳过X个数据,读取Y个数据

在这里插入图片描述


SELECT * FROM task_tasks ORDER BY taskid LIMIT 5 OFFSET 3
offset X是跳过X个数据,limit Y是选取Y个数据

在这里插入图片描述


6.使用注释:注释使用-- (两个连字符)嵌在行内。-- 之后的文本就是注释
SELECT prod_name -- 这是一条注释
FROM Products; 

第 3 课 排序检索数据

1.子句(clause)
SQL 语句由子句构成,有些子句是必需的,有些则是可选的。一个子
句通常由一个关键字加上所提供的数据组成。子句的例子有我们在前
一课看到的 SELECT 语句的 FROM 子句。

2.ORDER BY 子句取一个或多个列的名字,据此对输出进行排序。
3.排序数据

SELECT prod_name
FROM Products
ORDER BY prod_name; 

ORDER BY 子句的位置
在指定一条 ORDER BY 子句时,应该保证它是 SELECT 语句中最后一条子句。
如果它不是最后的子句,将会出现错误消息。

4.按多个列排序

SELECT prod_id, prod_price, prod_name
FROM Products
ORDER BY prod_price, prod_name; 
检索 3 个列,并按其中两个列对结果进行排序——首先按价
格,然后按名称排序
多个列排序应用在:姓名排序—首先按姓排序,然后在每个姓中再按名排序

5.按列位置排序—不懂

按列位置排序
SELECT prod_id, prod_price, prod_name
FROM Products
ORDER BY 2, 3; 
SELECT 清单中指定的是选择列的相对位置而不是列名。ORDER BY 2
表示按 SELECT 清单中的第二个列 prod_name 进行排序。ORDER BY 2,
3 表示先按 prod_price,再按 prod_name 进行排序

在这里插入图片描述
在这里插入图片描述
6.指定排序方向
升序—默认的排序顺序(ASC为升序,也可以指定)
降序—DESC
DESC关键字只应用到直接位于其前面的列名

SELECT prod_id, prod_price, prod_name
FROM Products
ORDER BY prod_price DESC; 
SELECT prod_id, prod_price, prod_name
FROM Products
ORDER BY prod_price DESC, prod_name; 
DESC关键字只应用到直接位于其前面的列名。
在上例中,只对prod_price列指定 DESC,对 prod_name 列不指定。
因此,prod_price 列以降序排序,
而 prod_name 列(在每个价格内)仍然按标准的升序排序

在多个列上降序排序如果想在多个列上进行降序排序,必须对每一列指定 DESC 关键字

第 4 课 过滤数据

  1. 使用 WHERE 子句

  2. 只检索所需数据需要指定搜索条件(search criteria),搜索条件也称为过滤条件

  3. 在 SELECT 语句中,数据根据 WHERE 子句中指定的搜索条件进行过滤。WHERE 子句在表名(FROM 子句)之后给出

SELECT prod_name, prod_price
FROM Products
WHERE prod_price = 3.49; 
  1. WHERE 子句的位置:在同时使用 ORDER BY 和 WHERE 子句时,应该让 ORDER BY 位于WHERE 之后,否则将会产生错误
  2. WHERE 子句操作符
    在这里插入图片描述
  3. 检查单个值
SELECT prod_name, prod_price
FROM Products
WHERE prod_price < 10; 
列出所有价格小于 10 美元的产品。
  1. 不匹配检查
SELECT vend_id, prod_name
FROM Products
WHERE vend_id <> 'DLL01'; 
列出所有不是供应商 DLL01 制造的产品
两个效果相同
SELECT vend_id, prod_name
FROM Products
WHERE vend_id != 'DLL01'; 
  1. 何时使用引号
    如果仔细观察上述 WHERE 子句中的条件,会看到有的值括在单引号内,
    而有的值未括起来。单引号用来限定字符串。如果将值与字符串类型的
    列进行比较,就需要限定引号。用来与数值列进行比较的值不用引号
  2. 范围值检查:BETWEEN 操作符(需要两个值,即范围的开始值和结束值)
SELECT prod_name, prod_price
FROM Products
WHERE prod_price BETWEEN 5 AND 10; 
检索价格在 5 美元和 10美元之间的所有产品
  1. 空值检查
    在创建表时,表设计人员可以指定其中的列能否不包含值。
    在一个列不包含值时,称其包含空值 NULL
    NULL:无值(no value),它与字段包含 0、空字符串或仅仅包含空格不同
SELECT prod_name
FROM Products
WHERE prod_price IS NULL;
返回所有没有价格(空 prod_price 字段,不是价格为 0)的产品
  1. NULL 和非匹配
    通过过滤选择不包含指定值的所有行时,你可能希望返回含 NULL 值
    的行。但是这做不到。因为未知(unknown)有特殊的含义,数据库
    不知道它们是否匹配,所以在进行匹配过滤或非匹配过滤时,不会返
    回这些结果。
    过滤数据时,一定要验证被过滤列中含 NULL 的行确实出现在返回的
    数据中。

第 5 课 高级数据过滤

  1. 组合 WHERE 子句
    SQL 允许给出多个 WHERE 子句。这些子句有两种使用方式,
    即以 AND 子句或 OR 子句的方式使用
  2. 操作符(operator):用来联结或改变 WHERE 子句中的子句的关键字,也称为逻辑操作符(logical operator)
  3. AND操作符:要通过不止一个列进行过滤,可以使用 AND 操作符给 WHERE 子句附加条件(and后的条件要连着where都满足才能筛选出结果)
SELECT prod_id, prod_price, prod_name
FROM Products
WHERE vend_id = 'DLL01' AND prod_price <= 4; 
  1. AND:用在 WHERE 子句中的关键字,用来指示检索满足所有给定条件的行(子句只包含一个 AND 子句,因此最多有两个过滤条件)
SELECT * FROM task_tasks WHERE `status`=1 AND userid=1
ORDER BY builddate

在这里插入图片描述

  1. OR操作符:OR 操作符与 AND 操作符正好相反,它指示 DBMS 检索匹配任一条件的行【事实上,许多 DBMS 在 OR WHERE 子句的第一个条件得到满足的情况下,就不再计算第二个条件了(在第一个条件满足时,不管第二个条件是否满足,相应的行都将被检索出来)。】
SELECT prod_name, prod_price
FROM Products
WHERE vend_id = 'DLL01' OR vend_id = ‘BRS01’; 

在这里插入图片描述

  1. 求值顺序
SELECT prod_name, prod_price
FROM Products
WHERE vend_id = 'DLL01' OR vend_id = 'BRS01'
AND prod_price >= 10; 
需要列出价格为10美元及以上,且由DLL01或BRS01
制造的所有产品
SELECT * FROM task_tasks WHERE taskname='旅游' OR taskname='哈哈哈1'
AND builddate ='2007-03-06'

在这里插入图片描述

  1. 在 WHERE 子句中使用圆括号
    任何时候使用具有 AND 和 OR 操作符的 WHERE 子句,都应该使用圆括号明确地分组操作符。
    不要过分依赖默认求值顺序,即使它确实如你希望的那样。
    使用圆括号没有什么坏处,它能消除歧义
    在这里插入图片描述

  1. IN 操作符:IN 操作符用来指定条件范围,范围中的每个条件都可以进行匹配。IN 取一组由逗号分隔、括在圆括号中的合法值
SELECT prod_name, prod_price
FROM Products
WHERE vend_id IN ( 'DLL01', 'BRS01' )
ORDER BY prod_name; 
此 SELECT 语句检索由供应商 DLL01 和 BRS01 制造的所有产品。
IN 操作符后跟由逗号分隔的合法值,这些值必须括在圆括号中。

你可能会猜测 IN 操作符完成了与 OR 相同的功能,恭喜你猜对了!下面
的 SQL 语句完成与上面的例子相同的工作
SELECT prod_name, prod_price
FROM Products
WHERE vend_id = 'DLL01' OR vend_id = 'BRS01'
ORDER BY prod_name; 
  1. IN操作符:WHERE 子句中用来指定要匹配值的清单的关键字,功能与 OR 相当。
  2. NOT 操作符
    WHERE 子句中的 NOT 操作符有且只有一个功能,那就是否定其后所跟的任何条件。因为 NOT 从不单独使用(它总是与其他操作符一起使用),所以它的语法与其他操作符有所不同。NOT 关键字可以用在要过滤的列前,而不仅是在其后
  3. NOT操作符:WHERE 子句中用来否定其后条件的关键字
SELECT prod_name
FROM Products
WHERE NOT vend_id = 'DLL01'
ORDER BY prod_name; 
列出除 DLL01 之外的所有供应商制造的产品

上面的例子也可以使用<>操作符来完成
SELECT prod_name
FROM Products
WHERE vend_id <> 'DLL01'
ORDER BY prod_name; 
SELECT * FROM task_tasks WHERE NOT `status`=1 ORDER BY builddate

在这里插入图片描述

  1. NOT优势:在与 IN 操作符联合使用时,NOT 可以非常简单地找出与条件列表不匹配的行。

第 6 课 用通配符进行过滤

通配符:百分号(%)、下划线(_)、方括号([ ])、(+)或(||)、

  1. LIKE 操作符
    通配符(wildcard)
    用来匹配值的一部分的特殊字符
    搜索模式(search pattern)
    由字面值、通配符或两者组合构成的搜索条件。
  2. 通配符本身实际上是 SQL 的 WHERE 子句中有特殊含义的字符,SQL 支持
    几种通配符。
    为在搜索子句中使用通配符,必须使用 LIKE 操作符。LIKE指示 DBMS,后跟的搜索模式利用通配符匹配而不是简单的相等匹配进行比较
    注意:通配符搜索只能用于文本字段(字符串),非文本数据类型字段不能使用通配符搜索。
  3. 百分号(%)通配符:最常使用的通配符是百分号(%)。在搜索串中,%表示任何字符出现任意次数
SELECT prod_id, prod_name
FROM Products
WHERE prod_name LIKE 'Fish%'; 
找出所有以词 Fish 起头的产品
SELECT * FROM task_tasks WHERE taskname LIKE '%放假%'

在这里插入图片描述

  1. Access 通配符:如果使用的是 Microsoft Access,需要使用*而不是%
  2. 区分大小写
    根据 DBMS 的不同及其配置,搜索可以是区分大小写的。如果区分大小写,则’fish%'与 Fish bean bag toy 就不匹配
  3. 通配符可在搜索模式中的任意位置使用,并且可以使用个通配符
  4. 搜索模式'%bean bag%'表示匹配任何位置上包含文本 bean bag 的值,
    不论它之前或之后出现什么字符
    注意:需要特别注意,除了能匹配一个或多个字符外,%还能匹配 0 个字符。%代表搜索模式中给定位置的 0 个、1 个或多个字符
    请注意 NULL
    通配符%看起来像是可以匹配任何东西,但有个例外,这就是 NULL。
    子句 WHERE prod_name LIKE '%'不会匹配产品名称为 NULL 的行
  5. 下划线(_)通配符:下划线的用途与%一样,但它只匹配单个字符,而不是多个字符
SELECT prod_id, prod_name
FROM Products
WHERE prod_name LIKE '__ inch teddy bear';

在这里插入图片描述

SELECT * FROM task_tasks WHERE taskname LIKE '放_'

在这里插入图片描述

一个下划线占一位
SELECT * FROM task_tasks WHERE taskname LIKE '放假__'

在这里插入图片描述
与%能匹配 0 个字符不同,_总是刚好匹配一个字符,不能多也不能少

  1. 方括号([ ])通配符:用来指定一个字符集,它必须匹配指定位置(通配符的位置)的一个字符
  2. 并不总是支持集合
    与前面描述的通配符不一样,并不是所有 DBMS 都支持用来创建集合的[]。只有微软的 Access 和 SQL Server 支持集合。为确定你使用的DBMS 是否支持集合,请参阅相应的文档。
FROM Customers
WHERE cust_contact LIKE '[JM]%'
ORDER BY cust_contact; 

在这里插入图片描述
在这里插入图片描述

第 7 课 创建计算字段

  1. 计算字段并不实际存在于数据库表中。计算字段是运行时在 SELECT 语句内
    创建的
  2. 字段(field)
    基本上与列(column)的意思相同,经常互换使用,不过数据库列一般称为列,而术语字段通常与计算字段一起使用
    需要特别注意,只有数据库知道 SELECT 语句中哪些列是实际的表列,哪些列是计算字段。从客户端(如应用程序)来看,计算字段的数据与其他列的数据的返回方式相同
  3. 拼接字段—解决办法是把两个列拼接起来:加号(+)或两个竖杠(||)表示
    拼接(concatenate):将值联结到一起(将一个值附加到另一个值)构成单个值
SELECT vend_name + ' (' + vend_country + ')'
FROM Vendors
ORDER BY vend_name;
-----------------------
SELECT vend_name || ' (' || vend_country || ')'
FROM Vendors
ORDER BY vend_name; 
-----------------
许多数据库(不是所有)保存填充为列宽的文本值,而实际上你要的结果不需要这些空格。
为正确返回格式化的数据,必须去掉这些空格。这可以使用 SQL 的 RTRIM()函数来完成
SELECT RTRIM(vend_name) + ' (' + RTRIM(vend_country) + ')'
FROM Vendors
ORDER BY vend_name; 
RTRIM()函数去掉值右边的所有空格。

在这里插入图片描述
去除空格之后的输出

在这里插入图片描述

  1. TRIM 函数
    大多数 DBMS 都支持 RTRIM()(正如刚才所见,它去掉字符串右边的空格)、LTRIM()(去掉字符串左边的空格)以及 TRIM()(去掉字符串左右两边的空格)。
  2. 别名(alias)是一个字段或值的替换名。别名用 AS 关键字赋予
SELECT 
taskid AS '任务id' ,
taskname AS '任务名称' ,
`status` AS'完成情况',
userid AS '用户id',
builddate as '创建任务日期'

FROM task_tasks

在这里插入图片描述

  1. 执行算术计算
    计算字段的另一常见用途是对检索出的数据进行算术计算
SELECT prod_id, quantity, item_price
FROM OrderItems
WHERE order_num = 20008; 
Orders 表包含收到的所有订单,OrderItems 表包含每个订单中的各项物品
检索订单号 20008 中的所有物品

第 8 课 使用函数处理数据

  • 函数:与大多数其他计算机语言一样,SQL 也可以用函数来处理数据
    在这里插入图片描述
  • 可移植(portable):所编写的代码可以在多个系统上运行
  • 使用函数
    使用函数的一些情况:
     用于处理文本字符串(如删除或填充值,转换值为大写或小写)的文本函数。
     用于在数值数据上进行算术操作(如返回绝对值,进行代数运算)的数值函数。
     用于处理日期和时间值并从这些值中提取特定成分(如返回两个日期之差,检查日期有效性)的日期和时间函数。
     返回 DBMS 正使用的特殊信息(如返回用户登录信息)的系统函数

4-1.文本处理函数

  • 使用 RTRIM()函数来去除列值右边的空格
  • 使用的是 UPPER()函数-UPPER()将文本转换为大写
    在这里插入图片描述
    4-2.日期和时间处理函数
SELECT order_num
FROM Orders
WHERE DATEPART(yy, order_date) = 2012; 

在这里插入图片描述

这个例子(SQL Server和Sybase版本以及Access版本)使用了DATEPART()函数,顾名思义,此函数返回日期的某一部分。
DATEPART()函数有两个参数,它们分别是返回的成分和从中返回成分的日期。
在此例子中,DATEPART()只从 order_date 列中返回年份。通过与 2012 比较,WHERE子句只过滤出此年份的订单

使用名为 DATE_PART()的类似函数的 PostgreSQL 版本
SELECT order_num
FROM Orders
WHERE DATE_PART('year', order_date) = 2012; 

4-3.数值处理函数
在这里插入图片描述

第 9 课 汇总数据

  1. 聚集函数(aggregate function):对某些行运行的函数,计算并返回一个值
    都需要汇总表中的数据,而不需要实际数据本身
    在这里插入图片描述

  2. AVG()函数:过对表中行数计数并计算其列值之和,求得该列的平均值
    AVG()可用来返回所有列的平均值,也可以用来返回特定列或行的平均值

SELECT AVG(`status`) 
FROM task_tasks

在这里插入图片描述

  1. 只用于单个列
    AVG()只能用来确定特定数值列的平均值,而且列名必须作为函数参数给出。
    为了获得多个列的平均值,必须使用多个 AVG()函数。

  2. NULL 值:AVG()函数忽略列值为 NULL 的行

  3. COUNT()函数:行计数。可利用 COUNT()确定表中行的数目或符合特定条件的行的数目

  4. COUNT()函数有两种使用方式:
     使用 COUNT(*)对表中行的数目进行计数,不管表列中包含的是空值(NULL)还是非空值
     使用 COUNT(column)对特定列中具有值的行进行计数,忽略 NULL 值。

SELECT COUNT(taskid) 
FROM task_tasks

在这里插入图片描述

SELECT COUNT(*) 
FROM task_tasks

在这里插入图片描述

  1. NULL 值
    如果指定列名,则 COUNT()函数会忽略指定列的值为空的行,
    但如果COUNT()函数中用的是星号(*),则不忽略
  2. MAX()函数:返回指定列中的最大值
SELECT MAX(`status`) 
FROM task_tasks

在这里插入图片描述

  1. 对非数值数据使用 MAX()
    虽然 MAX()一般用来找出最大的数值或日期值,但许多(并非所有)DBMS 允许将它用来返回任意列中的最大值,包括返回文本列中的最大值。
    在用于文本数据时,MAX()返回按该列排序后的最后一行
  2. NULL 值:MAX()函数忽略列值为 NULL 的行
  3. MIN()函数:返回指定列的最小值
SELECT MIN(`status`) 
FROM task_tasks

在这里插入图片描述

  1. 对非数值数据使用 MIN()
    虽然 MIN()一般用来找出最小的数值或日期值,但许多(并非所有)DBMS 允许将它用来返回任意列中的最小值,包括返回文本列中的最小值。
    在用于文本数据时,MIN()返回该列排序后最前面的行
  2. NULL 值:MIN()函数忽略列值为 NULL 的行
  3. SUM()函数:返回指定列值的和(总计)。
SELECT SUM(`status`) 
FROM task_tasks

在这里插入图片描述

  1. SUM()函数忽略列值为 NULL 的行

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

第 10 课 分组数据

SELECT 语句子句:GROUP BY 子句和 HAVING 子句

  1. 数据分组
SELECT COUNT(*) AS num_prods
FROM Products
WHERE vend_id = 'DLL01';
  1. 创建分组——groupby
SELECT vend_id, COUNT(*) AS num_prods
FROM Products
GROUP BY vend_id
SELECT `status` FROM task_tasks 
GROUP BY `status`

在这里插入图片描述

  1. GROUP BY 子句必须出现在 WHERE 子句之后ORDER BY 子句之前
  2. 过滤分组:HAVING 子句
    目前为止所学过的所有类型的 WHERE 子句都可以用 HAVING 来替代。
    唯一的差别是,WHERE过滤行,而 HAVING 过滤分组(HAVING 支持所有 WHERE 操作符 )
SELECT cust_id, COUNT(*) AS orders
FROM Orders
GROUP BY cust_id
HAVING COUNT(*) >= 2;
过滤 COUNT(*) >= 2(两个以上订单)的那些分组

在这里插入图片描述

  1. HAVING 和 WHERE 的差别
    这里有另一种理解方法,WHERE 在数据分组前进行过滤,HAVING 在数据分组后进行过滤。这是一个重要的区别,WHERE 排除的行不包括在分组中。这可能会改变计算值,从而影响 HAVING 子句中基于这些值过滤掉的分组
SELECT vend_id, COUNT(*) AS num_prods
FROM Products
WHERE prod_price >= 4
GROUP BY vend_id
HAVING COUNT(*) >= 2; 
列出具有两个以上产品且其价格大于等于 4 的供应商

在这里插入图片描述

  1. 使用 HAVING 和 WHERE
    HAVING 与 WHERE 非常类似,如果不指定 GROUP BY,则大多数 DBMS会同等对待它们。不过,你自己要能区分这一点。
    使用 HAVING 时应该结合 GROUP BY 子句,而 WHERE 子句用于标准的行级过滤
  2. 分组和排序
    order by和group by差异
    在这里插入图片描述
SELECT order_num, COUNT(*) AS items
FROM OrderItems
GROUP BY order_num
HAVING COUNT(*) >= 3; 
检索包含三个或更多物品的订单号和订购物品的数目

在这里插入图片描述

SELECT order_num, COUNT(*) AS items
FROM OrderItems
GROUP BY order_num
HAVING COUNT(*) >= 3
ORDER BY items, order_num; 
要按订购物品的数目排序输出,需要添加 ORDER BY 子句,

在这里插入图片描述
在这里插入图片描述

  1. SELECT 子句顺序
    在这里插入图片描述

第 11 课 使用子查询

  1. 子查询
    SELECT 语句是 SQL 的查询。我们迄今为止所看到的所有 SELECT 语句都
    是简单查询,即从单个数据库表中检索数据的单条语句
  2. 查询(query)
    任何 SQL 语句都是查询。但此术语一般指 SELECT 语句。
  3. 利用子查询进行过滤(where)
    IN 操作符允许我们在 WHERE 子句中规定多个值
语法
SELECT column_name(s)
FROM table_name
WHERE column_name IN (value1,value2,...)
SELECT cust_id
FROM Orders
WHERE order_num IN (SELECT order_num
 FROM OrderItems
 WHERE prod_id = 'RGAN01'); 

在 SELECT 语句中,子查询总是从内向外处理

SELECT cust_name, cust_contact 
FROM Customers
WHERE cust_id IN (SELECT cust_id
FROM Orders
WHERE order_num IN (SELECT order_num
FROM OrderItems
WHERE prod_id = 'RGAN01'));
为了执行上述 SELECT 语句,DBMS 实际上必须执行三条 SELECT 语句。
最里边的子查询返回订单号列表,此列表用于其外面的子查询的 WHERE
子句。外面的子查询返回顾客 ID 列表,此顾客 ID 列表用于最外层查询
的 WHERE 子句。最外层查询返回所需的数据

在这里插入图片描述

  1. 作为计算字段使用子查询
SELECT COUNT(*) AS orders
FROM Orders
WHERE cust_id = '1000000001'; 
码对顾客 1000000001 的订单进行计数
-------------------------
要对每个顾客执行 COUNT(*),应该将它作为一个子查询
SELECT cust_name,
 cust_state,
 (SELECT COUNT(*)
 FROM Orders
 WHERE Orders.cust_id = Customers.cust_id) AS orders
FROM Customers
ORDER BY cust_name; 


这条 SELECT 语句对 Customers 表中每个顾客返回三列:
cust_name、cust_state 和 orders。orders 是一个计算字段,
它是由圆括号中的子查询建立的。
该子查询对检索出的每个顾客执行一次。
在此例中,该子查询执行了 5 次,因为检索出了 5 个顾客。

子查询中的 WHERE 子句与前面使用的 WHERE 子句稍有不同,
因为它使用了完全限定列名,而不只是列名( cust_id)。
它指定表名和列名Orders.cust_id 和 Customers.cust_id)。
下面的 WHERE 子句告诉 SQL,
比较Orders表中的cust_id和当前正从Customers表中检索的cust_id:
WHERE Orders.cust_id = Customers.cust_id用一个句点分隔表名和列名,
在有可能混淆列名时必须使用这种语法。
在这个例子中,有两个 cust_id 列:一个在 Customers 中,另一个在Orders 中。
如果不采用完全限定列名,DBMS 会认为要对 Orders 表中的 cust_id 自身进行比较。
因为SELECT COUNT(*) FROM Orders WHERE cust_id = cust_id
总是返回 Orders 表中订单的总数,而这个结果不是我们想要的:

在这里插入图片描述
在这里插入图片描述

  1. 子查询常用于 WHERE 子句的 IN 操作符中,以及用来填充计算列

第 12 课 联结表

  1. SQL 最强大的功能之一就是能在数据查询的执行中联结(join)表
  2. 关系表
  3. 为什么使用联结?将数据分解为多个表能更有效地存储,更方便地处理,并且
    可伸缩性更好

如果数据存储在多个表中,怎样用一条 SELECT 语句就检索出数据呢?
答案是使用联结。
简单说,联结是一种机制,用来在一条 SELECT 语句中关联表,因此称为联结。
使用特殊的语法,可以联结多个表返回一组输出,联结在运行时关联表中正确的行

  1. 创建联结:指定要联结的所有表以及关联它们的方式即可
SELECT vend_name, prod_name, prod_price
FROM Vendors, Products
WHERE Vendors.vend_id = Products.vend_id; 
要匹配的两列指定为 Vendors.vend_id 和 Products.vend_id。
这里需要这种完全限定列名,
内联
检索所有顾客及其订单
SELECT Customers.cust_id, Orders.order_num
FROM Customers INNER JOIN Orders
 ON Customers.cust_id = Orders.cust_id; 
  1. WHERE子句的重要性
    在联结两个表时,实际要做的是将第一个表中的每一行与第二个表中的每一行配对。WHERE 子句作为过滤条件,只包含那些匹配给定条件(这里是联结条件)的行。
    没有 WHERE子句,第一个表中的每一行将与第二个表中的每一行配对,而不管它们逻辑上是否能配在一起
  2. 笛卡儿积(cartesian product)
    由没有联结条件的表关系返回的结果为笛卡儿积。检索出的行的数目将是第一个表中的行数乘以第二个表中的行数
  3. 不要忘了 WHERE 子句
    要保证所有联结都有 WHERE 子句,否则 DBMS 将返回比想要的数据多得多的数据。同理,要保证 WHERE 子句的正确性
  4. 内联结inner join(等值联结)
SELECT vend_name, prod_name, prod_price
FROM Vendors INNER JOIN Products
ON Vendors.vend_id = Products.vend_id; 
  1. 联结多个表
SELECT prod_name, vend_name, prod_price, quantity
FROM OrderItems, Products, Vendors
WHERE Products.vend_id = Vendors.vend_id
AND OrderItems.prod_id = Products.prod_id
AND order_num = 20007; 
这个例子显示订单 20007 中的物品。订单物品存储在 OrderItems 表中。
每个产品按其产品 ID 存储,它引用 Products 表中的产品。这些产品通
过供应商 ID 联结到 Vendors 表中相应的供应商,供应商 ID 存储在每个
产品的记录中。这里的 FROM 子句列出三个表,WHERE 子句定义这两个联
结条件,而第三个联结条件用来过滤出订单 20007 中的物品

在这里插入图片描述

  1. 性能考虑
    DBMS 在运行时关联指定的每个表,以处理联结。这种处理可能非常耗费资源,因此应该注意,不要联结不必要的表。
    联结的表越多,性能下降越厉害
SELECT cust_name, cust_contact
FROM Customers
WHERE cust_id IN (SELECT cust_id
FROM Orders
WHERE order_num IN (SELECT order_num
FROM OrderItems
WHERE prod_id = 'RGAN01')); 
以上等效为
SELECT cust_name, cust_contact
FROM Customers, Orders, OrderItems
WHERE Customers.cust_id = Orders.cust_id
AND OrderItems.order_num = Orders.order_num
AND prod_id = 'RGAN01'; 

第 13 课 创建高级联结

如何使用表别名,如何对被联结的表使用聚集函数

  1. 使用表别名:主要原因是能在一条 SELECT 语句中不止一次引用相同的表
给字段起别名
SELECT RTRIM(vend_name) + ' (' + RTRIM(vend_country) + ')'
AS vend_title
FROM Vendors
ORDER BY vend_name; 

给表起别名
SELECT cust_name, cust_contact
FROM Customers AS C, Orders AS O, OrderItems AS OI
WHERE C.cust_id = O.cust_id
AND OI.order_num = O.order_num
AND prod_id = 'RGAN01'; 
  1. 使用不同类型的联结
    内联结或等值联结
    自联结(self-join)
    自然联结(natural join)
    外联结(outer join)
  2. 自联结:
预期效果:给与 Jim Jones 同一公司的所有顾客发送一封信件。这个查询要求
首先找出 Jim Jones 工作的公司,然后找出在该公司工作的顾客
写法一:
SELECT cust_id, cust_name, cust_contact
FROM Customers
WHERE cust_name = (SELECT cust_name
FROM Customers
WHERE cust_contact = 'Jim Jones'); 
方法二:连表(此表是相同一张)
SELECT c1.cust_id, c1.cust_name, c1.cust_contact
FROM Customers AS c1, Customers AS c2
WHERE c1.cust_name = c2.cust_name
AND c2.cust_contact = 'Jim Jones'; 
  1. 用自联结而不用子查询
    自联结通常作为外部语句,用来替代从相同表中检索数据的使用子查询语句。
    虽然最终的结果是相同的,但许多 DBMS 处理联结远比处理子查询快得多
  2. 自然联结:标准的联结(前一课中介绍的内联结)返回所有数据,相同的列甚至多次出现。自然联结排除多次出现,使每一列只返回一次
SELECT C.*, O.order_num, O.order_date,
OI.prod_id, OI.quantity, OI.item_price
FROM Customers AS C, Orders AS O, OrderItems AS OI
WHERE C.cust_id = O.cust_id
AND OI.order_num = O.order_num
AND prod_id = 'RGAN01'; 
在这个例子中,通配符只对第一个表使用。所有其他列明确列出,
所以没有重复的列被检索出来

事实上,我们迄今为止建立的每个内联结都是自然联结,很可能永远都
不会用到不是自然联结的内联结

  1. 外联结:许多联结将一个表中的行与另一个表中的行相关联,但有时候需要包含
    没有关联行的那些行。
外联——左联
检索包括没有订单顾客在内的所有顾客
SELECT Customers.cust_id, Orders.order_num
FROM Customers LEFT OUTER JOIN Orders
ON Customers.cust_id = Orders.cust_id; 

外联——右联
SELECT Customers.cust_id, Orders.order_num
FROM Customers RIGHT OUTER JOIN Orders
ON Orders.cust_id = Customers.cust_id; 

在这里插入图片描述

  1. 是全外联结(full outer join):它检索两个表中的所有行并关联那些可以关联的行。与左外联结或右外联结包含一个表的不关联的行不同,全外联结包含两个表的不关联的行
SELECT Customers.cust_id, Orders.order_num
FROM Orders FULL OUTER JOIN Customers
ON Orders.cust_id = Customers.cust_id; 
  1. 使用带聚集函数的联结
检索所有顾客及每个顾客所下的订单数,使用 COUNT()函数完成
SELECT Customers.cust_id,
 COUNT(Orders.order_num) AS num_ord
FROM Customers INNER JOIN Orders
 ON Customers.cust_id = Orders.cust_id
GROUP BY Customers.cust_id; 

在这里插入图片描述

  1. 聚集函数也可以方便地与其他联结一起使用
外联-左联
SELECT Customers.cust_id,
 COUNT(Orders.order_num) AS num_ord
FROM Customers LEFT OUTER JOIN Orders
 ON Customers.cust_id = Orders.cust_id
GROUP BY Customers.cust_id;
  1. 使用联结和联结条件
     注意所使用的联结类型。一般我们使用内联结,但使用外联结也有效。
     关于确切的联结语法,应该查看具体的文档,看相应的 DBMS 支持何
    种语法(大多数 DBMS 使用这两课中描述的某种语法)。
     保证使用正确的联结条件(不管采用哪种语法),否则会返回不正确
    的数据。
     应该总是提供联结条件,否则会得出笛卡儿积。
     在一个联结中可以包含多个表,甚至可以对每个联结采用不同的联结
    类型。虽然这样做是合法的,一般也很有用,但应该在一起测试它们
    前分别测试每个联结。这会使故障排除更为简单。

第 14 课 组合查询

复合查询:
SQL 也允许执行多个查询(多条 SELECT 语句),并将结果作为一
个查询结果集返回。这些组合查询通常称为并(union)或复合查询

  1. 主要有两种情况需要使用组合查询:
     在一个查询中从不同的表返回结构数据;
     对一个表执行多个查询,按一个查询返回数据
  2. 创建组合查询
    可用 UNION 操作符来组合数条 SQL 查询。利用 UNION,可给出多条
    SELECT 语句,将它们的结果组合成一个结果集
  3. 使用UNION
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI')
UNION
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_name = 'Fun4All';

等效于
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI')
 OR cust_name = 'Fun4All
  1. UNION规则
     UNION 必须由两条或两条以上的 SELECT 语句组成,语句之间用关键
    字UNION分隔(因此,如果组合四条SELECT语句,将要使用三个UNION
    关键字)。
     UNION 中的每个查询必须包含相同的列、表达式或聚集函数(不过,
    各个列不需要以相同的次序列出)。
     列数据类型必须兼容:类型不必完全相同,但必须是 DBMS 可以隐含
    转换的类型(例如,不同的数值类型或不同的日期类型)。
  2. 包含或取消重复的行:UNION 从查询结果集中自动去除了重复的行;换句话说,它的行为与一条 SELECT 语句中使用多个 WHERE 子句条件一样。
    这是 UNION 的默认行为,如果愿意也可以改变它。事实上,如果想返回
    所有的匹配行
    ,可使用 UNION ALL 而不是 UNION。
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI')
UNION ALL
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_name = 'Fun4All'; 
  1. UNION 与 WHERE
    这一课一开始我们说过,UNION 几乎总是完成与多个 WHERE 条件相同
    的工作。UNION ALL 为 UNION 的一种形式,它完成 WHERE 子句完成
    不了的工作。如果确实需要每个条件的匹配行全部出现(包括重复行),
    就必须使用 UNION ALL,而不是 WHERE
  2. 对组合查询结果排序
    SELECT 语句的输出用 ORDER BY 子句排序。在用 UNION 组合查询时,只能使用一条 ORDER BY 子句,它必须位于最后一条 SELECT 语句之后。
    对于结果集,不存在用一种方式排序一部分,
    而又用另一种方式排序另一部分的情况,因此不允许使用多条 ORDER BY 子句
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI')
UNION
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_name = 'Fun4All'
ORDER BY cust_name, cust_contact; 

在这里插入图片描述

第 15 课 插入数据

利用 SQL 的 INSERT 语句将数据插入表中

  1. INSERT 用来将行插入(或添加)到数据库表。插入有几种方式:
     插入完整的行;
     插入行的一部分;
     插入某些查询的结果
  2. 插入完整的行
INSERT INTO Customers
VALUES('1000000006',
 'Toy Land',
 '123 Any Street',
 'New York',
 'NY',
 '11111',
 'USA',
 NULL,
 NULL); 
 存储到表中每一列的数据在 VALUES 子句中给出,必须给每一列提供一个值
 如果某列没有值,如上面的 cust_contact 和 cust_email 列,则应该使用 NULL 值
 (假定表允许对该列指定空值)
 
  1. INTO 关键字
    在某些 SQL 实现中,跟在 INSERT 之后的 INTO 关键字是可选的。但
    是,即使不一定需要,最好还是提供这个关键字,这样做将保证 SQL
    代码在 DBMS 之间可移植。
INSERT INTO Customers(cust_id,
 cust_contact,
 cust_email,
 cust_name,
 cust_address,
 cust_city,
 cust_state,
 cust_zip)
VALUES('1000000006',
 NULL,
 NULL,
 'Toy Land',
 '123 Any Street',
 'New York',
 'NY',
 '11111'); 
 INSERT 语句填充所有列(与前面的一样),但以一种不同的次序填充
 因为给出了列名,所以插入结果仍然正确
  1. 插入部分行:使用这种语法,还可以省略列,这表示可以只给某些列提供值,给其他列不提供值。
INSERT INTO Customers(cust_id,
 cust_name,
 cust_address,
 cust_city,
 cust_state,
 cust_zip,
 cust_country)
VALUES('1000000006',
 'Toy Land',
 '123 Any Street',
 'New York',
 'NY',
 '11111',
 'USA'); 
没有给 cust_contact 和 cust_email 这两列提供值。
这表示没必要在 INSERT 语句中包含它们。因此,这里的 INSERT
语句省略了这两列及其对应的值
  1. 省略列
    如果表的定义允许,则可以在 INSERT 操作中省略某些列。省略的列必须满足以下某个条件。
     该列定义为允许 NULL 值(无值或空值)。
     在表定义中给出默认值。这表示如果不给出值,将使用默认值
  2. 省略所需的值
    如果表中不允许有 NULL 值或者默认值,这时却省略了表中的值,
    DBMS 就会产生错误消息,相应的行不能成功插入
  3. 插入检索出的数据

INSERT 一般用来给表插入具有指定列值的行。INSERT 还存在另一种
形式,可以利用它将 SELECT 语句的结果插入表中,这就是所谓的
INSERT SELECT。顾名思义,它是由一条 INSERT 语句和一条 SELECT
语句组成的

INSERT INTO Customers(cust_id,
 cust_contact,
 cust_email,
 cust_name,
 cust_address,
 cust_city,
 cust_state,
 cust_zip,
 cust_country)
SELECT cust_id,
 cust_contact,
 cust_email,
 cust_name,
 cust_address,
 cust_city,
 cust_state,
 cust_zip,
 cust_country
FROM CustNew;
假如想把另一表中的顾客列合并到 Customers 表中。
不需要每次读取一行再将它用 INSERT 插入
  1. :插入多行
    INSERT 通常只插入一行。要插入多行,必须执行多个 INSERT 语句。
    INSERT SELECT是个例外,它可以用一条INSERT插入多行,不管SELECT
    语句返回多少行,都将被 INSERT 插入。
    (INSERT SELECT 中 SELECT 语句可以包含 WHERE 子句,以过滤插入的数据)

  2. 从一个表复制到另一个表
    有一种数据插入不使用 INSERT 语句。要将一个表的内容复制到一个全新的表(运行中创建的表),可以使用 SELECT INTO 语句。

  3. 与 INSERT SELECT 将数据添加到一个已经存在的表不同,SELECT INTO
    将数据复制到一个新表(有的 DBMS 可以覆盖已经存在的表,这依赖于所使用的具体 DBMS
    INSERT SELECT 与 SELECT INTO
    它们之间的一个重要差别是前者导出数据,而后者导入数据。

SELECT INTO使用
SELECT *
INTO CustCopy
FROM Customers; 
这条 SELECT 语句创建一个名为 CustCopy 的新表,
并把 Customers 表的整个内容复制到新表中

MariaDB、MySQL、Oracle、PostgreSQL 和 SQLite 使用的语法稍有不同

第 16 课 更新和删除数据

更新(修改)表中的数据,可以使用 UPDATE 语句

  1. 有两种使用 UPDATE的方式:
     更新表中的特定行;
     更新表中的所有行
  2. 基本的 UPDATE 语句由三部分组成,分别是:
     要更新的表;
     列名和它们的新值;
     确定要更新哪些行的过滤条件
UPDATE Customers
SET cust_email = 'kim@thetoystore.com'
WHERE cust_id = '1000000005'; 
  1. SET 命令用来将新值赋给被更新的列
在更新多个列时,只需要使用一条 SET 命令,
每个“列=值”对之间用逗号分隔(最后一列之后不用逗号)

UPDATE Customers
SET cust_contact = 'Sam Roberts',
 cust_email = 'sam@toyland.com'
WHERE cust_id = '1000000006'; 
  1. 要删除某个列的值,可设置它为 NULL(假如表定义允许 NULL 值)
UPDATE Customers
SET cust_email = NULL
WHERE cust_id = '1000000005'; 
其中NULL用来去除cust_email列中的值。这与保存空字符串很不同(空
字符串用''表示,是一个值),而 NULL 表示没有值。
  1. 删除数据:使用 DELETE 语句
  2. 两种使用 DELETE的方式:
     从表中删除特定的行;
     从表中删除所有行。
DELETE FROM Customers
WHERE cust_id = '1000000006'; 

在这里插入图片描述
在这里插入图片描述

  1. DELETE 不需要列名或通配符。DELETE 删除整行而不是删除列。要删除
    指定的列,请使用 UPDATE 语句
  2. 删除表的内容而不是表
    DELETE 语句从表中删除行,甚至是删除表中所有行。但是,DELETE
    不删除表本身
  3. 更快的删除
    如果想从表中删除所有行,不要使用 DELETE。可使用 TRUNCATE TABLE
    语句,它完成相同的工作,而速度更快(因为不记录数据的变动)
  4. 更新和删除的指导原则
     除非确实打算更新和删除每一行,否则绝对不要使用不带 WHERE 子句
    的 UPDATE 或 DELETE 语句。
     保证每个表都有主键(如果忘记这个内容,请参阅第 12 课),尽可能
    像 WHERE 子句那样使用它(可以指定各主键、多个值或值的范围)。
     在 UPDATE 或 DELETE 语句使用 WHERE 子句前,应该先用 SELECT 进
    行测试,保证它过滤的是正确的记录,以防编写的 WHERE 子句不正确。
     使用强制实施引用完整性的数据库(关于这个内容,请参阅第 12 课),
    这样 DBMS 将不允许删除其数据与其他表相关联的行。
     有的 DBMS 允许数据库管理员施加约束,防止执行不带 WHERE 子句
    的 UPDATE 或 DELETE 语句。如果所采用的 DBMS 支持这个特性,应
    该使用它。
    若是 SQL没有撤销(undo)按钮,应该非常小心地使用 UPDATE 和 DELETE,
    否则你会发现自己更新或删除了错误的数据。

第 17 课 创建和操纵表

创建、更改和删除表的基本知识

  1. 创建表:SQL 不仅用于表数据操纵,还用来执行数据库和表的所有操作,包括表
    本身的创建和处理

  2. 两种创建表的方法:
     多数 DBMS 都具有交互式创建和管理数据库表的工具;
     表也可以直接用 SQL 语句操纵

  3. 表创建基础
    利用 CREATE TABLE 创建表,必须给出下列信息:
     新表的名字,在关键字 CREATE TABLE 之后给出;
     表列的名字和定义,用逗号分隔;
     有的 DBMS 还要求指定表的位置。
    4创建表名,命名:表名紧跟 CREATE TABLE 关键字.

  4. 使用NULL值
    NULL 值就是没有值或缺值。允许 NULL 值的列也允许在插入行时不给出该列的值。不允许 NULL 值的列不接受没有列值的行,换句话说,在插入或更新行时,该列必须有值(每个表列要么是 NULL 列,要么是 NOT NULL 列,这种状态在创建时由表
    的定义规定)
    在这里插入图片描述

  5. 理解Null
    在这里插入图片描述

  6. 指定默认值:关键字 DEFAULT 指定
    在这里插入图片描述

  7. 默认值经常用于日期或时间戳列。例如,通过指定引用系统日期的函数或变量,将系统日期用作默认日期。
    MySQL 用户指定 DEFAULT CURRENT_DATE(),
    Oracle 用户指定 DEFAULT SYSDATE,
    而 SQL Server用户指定 DEFAULT GETDATE()。
    遗憾的是,这条获得系统日期的命令在不同的 DBMS 中几乎都是不同的
    在这里插入图片描述

  8. 使用 DEFAULT 而不是 NULL 值
    许多数据库开发人员喜欢使用 DEFAULT 值而不是 NULL 列,对于用于
    计算或数据分组的列更是如此

  9. 更新表:用 ALTER TABLE 语句

ALTER TABLE Vendors
ADD vend_phone CHAR(20);
给 Vendors 表增加一个名为 vend_phone 的列,其数据类型为 CHAR 

ALTER TABLE Vendors
DROP COLUMN vend_phone; 
删除列
  1. 删除表:DROP TABLE 语句
DROP TABLE CustCopy; 
删除表没有确认,也不能撤销,执行这条语句将永久删除该表
  1. 重命名表:
    DB2、MariaDB、MySQL、Oracle 和 PostgreSQL 用户使用 RENAME语句,SQL Server 用户使用 sp_rename 存储过程,
    SQLite 用户使用 ALTERTABLE 语句

第 18 课 使用视图

介绍什么是视图,它们怎样工作,何时使用它们;还将讲述如
何利用视图简化前几课中执行的某些 SQL 操作

  1. 视图:视图是虚拟的表。与包含数据的表不一样,视图只包含使用时动态检索
    数据的查询
SELECT cust_name, cust_contact
FROM Customers, Orders, OrderItems
WHERE Customers.cust_id = Orders.cust_id
 AND OrderItems.order_num = Orders.order_num
 AND prod_id = 'RGAN01';
此查询用来检索订购了某种产品的顾客。任何需要这个数据的人都必须
理解相关表的结构,知道如何创建查询和对表进行联结。检索其他产品
(或多个产品)的相同数据,必须修改最后的 WHERE 子句。
现在,假如可以把整个查询包装成一个名为 ProductCustomers 的虚拟
表,则可以如下轻松地检索出相同的数据:
输入▼
SELECT cust_name, cust_contact
FROM ProductCustomers
WHERE prod_id = 'RGAN01'; 
  1. 为什么使用视图
     重用 SQL 语句
     简化复杂的 SQL 操作。在编写查询后,可以方便地重用它而不必知道
    其基本查询细节。
     使用表的一部分而不是整个表。
     保护数据。可以授予用户访问表的特定部分的权限,而不是整个表的
    访问权限。
     更改数据格式和表示。视图可返回与底层表的表示和格式不同的数据
  2. 视图仅仅是用来查看存储在别处数据的一种设施。
    视图本身不包含数据,因此返回的数据是从其他表中检索出来的。
    在添加或更改这些表中的数据时,视图将返回改变过的数据
  3. 创建视图:用 CREATE VIEW 语句
  4. 利用视图简化复杂的联结
输入▼
CREATE VIEW ProductCustomers AS
SELECT cust_name, cust_contact, prod_id
FROM Customers, Orders, OrderItems
WHERE Customers.cust_id = Orders.cust_id
 AND OrderItems.order_num = Orders.order_num;
分析▼
这条语句创建一个名为 ProductCustomers 的视图,它联结三个表,返
回已订购了任意产品的所有顾客的列表。如果执行 SELECT * FROM
ProductCustomers,将列出订购了任意产品的顾客
检索订购了产品 RGAN01 的顾客
输入▼
SELECT cust_name, cust_contact
FROM ProductCustomers
WHERE prod_id = 'RGAN01';

输出▼
cust_name cust_contact
------------------- ------------------
Fun4All Denise L. Stephens
The Toy Store Kim Howard 
详细看书介绍P160-165

第 19 课 使用存储过程

  1. 简单来说,存储过程就是为以后使用而保存的一条或多条 SQL 语句。
    可将其视为批文件,虽然它们的作用不仅限于批处理
  2. 为什么要使用存储过程
     通过把处理封装在一个易用的单元中,可以简化复杂的操作(如前面
    例子所述)。
     由于不要求反复建立一系列处理步骤,因而保证了数据的一致性。如
    果所有开发人员和应用程序都使用同一存储过程,则所使用的代码都
    是相同的。
    这一点的延伸就是防止错误。需要执行的步骤越多,出错的可能性就
    越大。防止错误保证了数据的一致性。
     简化对变动的管理。如果表名、列名或业务逻辑(或别的内容)有变
    化,那么只需要更改存储过程的代码。使用它的人员甚至不需要知道
    这些变化。
    这一点的延伸就是安全性。通过存储过程限制对基础数据的访问,减
    少了数据讹误(无意识的或别的原因所导致的数据讹误)的机会。
     因为存储过程通常以编译过的形式存储,所以 DBMS 处理命令所需的
    工作量少,提高了性能。
     存在一些只能用在单个请求中的 SQL 元素和特性,存储过程可以使用
    它们来编写功能更强更灵活的代码。
    换句话说,使用存储过程有三个主要的好处,即简单、安全、高性能。
    显然,它们都很重要。不过,在将 SQL 代码转换为存储过程前,也必须
    知道它的一些缺陷。
     不同 DBMS 中的存储过程语法有所不同。事实上,编写真正的可移植
    存储过程几乎是不可能的。不过,存储过程的自我调用(名字以及数
    据如何传递)可以相对保持可移植。因此,如果需要移植到别的DBMS,
    至少客户端应用代码不需要变动。
     一般来说,编写存储过程比编写基本 SQL 语句复杂,需要更高的技能,
    更丰富的经验。因此,许多数据库管理员把限制存储过程的创建作为
    安全措施(主要受上一条缺陷的影响)
  3. 执行存储过程
    执行存储过程的 SQL 语句很简单,即 EXECUTE。
    EXECUTE 接受存储过程名和需要传递给它的任何参数。
EXECUTE AddNewProduct( 'JTS01',
 'Stuffed Eiffel Tower',
 6.49,
 'Plush stuffed toy with the text La
➥Tour Eiffel in red white and blue' ); 

这里执行一个名为 AddNewProduct 的存储过程,将一个新产品添加到Products 表中。
AddNewProduct 有四个参数,分别是:
供应商 ID(Vendors 表的主键)、产品名、价格和描述。
这 4 个参数匹配存储过程中 4 个预期变量(定义为存储过程自身的组成部分)。
此存储过程将新行添加到 Products 表,并将传入的属性赋给相应的列

详细看书P170-174
  1. 创建存储过程

第 20 课 管理事务处理

介绍什么是事务处理,如何利用 COMMIT 和 ROLLBACK 语句管理事务处理

  1. 事务处理:
    通过确保成批的 SQL 操作
    要么完全执行,要么完全不执行,来维护数据库的完整性
  2. 可以回退哪些语句?
    事务处理用来管理 INSERT、UPDATE 和 DELETE 语句。不能回退 SELECT
    语句(回退 SELECT 语句也没有必要),也不能回退 CREATE 或 DROP 操
    作。事务处理中可以使用这些语句,但进行回退时,这些操作也不撤销
  3. 控制事务处理:
有的 DBMS要求明确标识事务处理块的开始和结束。如在 SQL Server中
BEGIN TRANSACTION
...
COMMIT TRANSACTION 
--------------------
MariaDB 和 MySQL 中等同的代码为:
START TRANSACTION
...
----------------
PostgreSQL 使用 ANSI SQL 语法:
输入▼
BEGIN
... 
---------
  1. 使用ROLLBACK:用来回退(撤销)SQL 语句
DELETE FROM Orders;
ROLLBACK; 
在此例子中,执行 DELETE 操作,然后用 ROLLBACK 语句撤销。虽然这不
是最有用的例子,但它的确能够说明,在事务处理块中,DELETE 操作(与
INSERT 和 UPDATE 操作一样)并不是最终的结果
  1. 使用COMMIT

第 21 课 使用游标

  1. 游标
    SQL 检索操作返回一组称为结果集的行,这组返回的行都是与 SQL 语句
    相匹配的行(零行或多行)。简单地使用 SELECT 语句,没有办法得到第
    一行、下一行或前 10 行
  2. 结果集(result set):SQL 查询所检索出的结果

第 22 课 高级 SQL 特性

几个高级数据处理特性:约束、索引和触发器

  1. 约束:管理如何插入或处理数据库数据的规则

  2. 主键:主键是一种特殊的约束,用来保证一列(或一组列)中的值是唯一的,而且永不改动
    在这里插入图片描述

ALTER TABLE Vendors
ADD CONSTRAINT PRIMARY KEY (vend_id);
  1. 外键:外键是表中的一列,其值必须列在另一表的主键中。外键是保证引用完
    整性的极其重要部分
    在这里插入图片描述
ALTER TABLE Orders
ADD CONSTRAINT
FOREIGN KEY (cust_id) REFERENCES Customers (cust_id) 
  1. 唯一约束:唯一约束用来保证一列(或一组列)中的数据是唯一的。它们类似于主

     表可包含多个唯一约束,但每个表只允许一个主键。
     唯一约束列可包含 NULL 值。
     唯一约束列可修改或更新。
     唯一约束列的值可重复使用。
     与主键不一样,唯一约束不能用来定义外键。
  2. 检查约束:检查约束用来保证一列(或一组列)中的数据满足一组指定的条件
    在这里插入图片描述
ADD CONSTRAINT CHECK (gender LIKE '[MF]') 

 检查最小或最大值。例如,防止 0 个物品的订单(即使 0 是合法的数)。
 指定范围。例如,保证发货日期大于等于今天的日期,但不超过今天
起一年后的日期。
 只允许特定的值。例如,在性别字段中只允许 M 或 F。

  1. 索引:用来排序数据以加快搜索和排序操作的速度

 索引改善检索操作的性能,但降低了数据插入、修改和删除的性能。
在执行这些操作时,DBMS 必须动态地更新索引。
 索引数据可能要占用大量的存储空间。
 并非所有数据都适合做索引。取值不多的数据(如州)不如具有更多
可能值的数据(如姓或名),能通过索引得到那么多的好处。
 索引用于数据过滤和数据排序。如果你经常以某种特定的顺序排序数
据,则该数据可能适合做索引。
 可以在索引中定义多个列(例如,州加上城市)。这样的索引仅在以州
加城市的顺序排序时有用。如果想按城市排序,则这种索引没有用处

在 Products 表的产品名列上创建一个简单的索引
CREATE INDEX prod_name_ind
ON Products (prod_name); 
索引必须唯一命名。这里的索引名 prod_name_ind 在关键字 CREATEINDEX 之后定义
ON 用来指定被索引的表,而索引中包含的列(此例中仅有一列)在表名后的圆括号中给出
  1. 触发器:是特殊的存储过程,它在特定的数据库活动发生时自动执行。 触发器可以与特定表上的 INSERT、UPDATE 和 DELETE 操作(或组合)相关联
  2. 与存储过程不一样(存储过程只是简单的存储 SQL 语句),触发器与单个的表相关联
  3. 触发器内的代码具有以下数据的访问权:
     INSERT 操作中的所有新数据;
     UPDATE 操作中的所有新数据和旧数据;
     DELETE 操作中删除的数据。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《SQL必知必会》是一本非常经典的SQL入门书籍,适合初学者快速掌握SQL语言的基本知识和技巧。本书主要分为四个部分:基础部分、检索部分、排序和分组以及高级数据操作。基础部分介绍了SQL的起源、数据库的类型、表的创建和插入数据等基本概念和操作。检索部分则详细讲解了如何使用SELECT语句来查询数据库中的数据,包括使用WHERE子句进行条件查询、使用AND和OR操作符进行多条件查询等常用技巧。排序和分组部分则介绍了如何对查询结果进行排序和分组处理,以及使用聚合函数计算汇总数据等内容。最后一个部分是高级数据操作,介绍了如何连接多个表、使用子查询进行嵌套查询、使用视图进行数据访问等高级技巧。在每个章节的最后都包含了习题和实例,可以帮助读者巩固所学知识。 这本书以简明易懂的语言,结合大量的实例和图表,帮助读者从零开始学习SQL语言。即使没有编程经验的读者也能够轻松理解和掌握其中的知识。《SQL必知必会》还提供了一个完整的SQL语法参考手册,方便读者在实践中查找和使用各种SQL语句和函数。 总的来说,《SQL必知必会》是一本对于学习SQL语言非常有帮助的入门书籍。无论是想要进一步学习数据库开发,还是需要使用SQL语言进行数据分析,都可以从这本书中得到很多有用的知识和技巧。 ### 回答2: 《SQL必知必会》是一本非常经典且实用的SQL入门教材。该书的主要目的是帮助初学者快速入门SQL语言,掌握SQL查询语言的基本知识和技巧。为了回答这个问题,我将从以下几个方面进行说明。 首先,该书在内容上涵盖了SQL的基础知识和常用操作。从数据的组织结构、关系型数据库的概念,到SQL语言的基本语法、数据查询、更新、删除和插入等操作,都有详细的介绍和示例。这样有助于读者快速掌握SQL的基本概念和常用操作。 其次,《SQL必知必会》以简单明了的语言和生动形象的案例讲解了SQL查询的各种方法和技巧。通过大量的实例,读者可以了解如何进行条件查询、多表查询、排序、分组、连接等操作,从而更好地理解SQL的语法和应用场景。 此外,该书还介绍了一些高级的SQL语句和技巧,如子查询、视图、事务、索引等。这些内容对于进一步提高SQL查询效率和优化数据库操作非常有帮助。 总的来说,《SQL必知必会》是一本非常适合初学者入门的SQL教材。它的内容涵盖了SQL的基础知识、常用操作和一些高级技巧。通过阅读这本书,读者可以快速了解SQL语言,并能够进行简单的查询和数据操作。不仅如此,这本书还以简单明了的语言和丰富的实例,帮助读者更好地理解和应用SQL语言。无论是想从事数据库开发、数据分析还是数据库管理员等相关职业的人,都可以通过阅读《SQL必知必会》来快速入门SQL,掌握必备的数据查询和操作技能。 ### 回答3: 《SQL必知必会》是由Ben Forta编写的一本经典的SQL入门教程。这本书以简单易懂的方式介绍了SQL语言的基本概念和常用操作,适合初学者和想要提升SQL技能的人阅读。 本书首先介绍了SQL的起源和概念,然后详细讲解了SQL的各种基本语句,包括创建表、插入数据、查询数据和更新数据等。书中通过大量的实例和图表,帮助读者理解和掌握SQL语句的用法和逻辑。 《SQL必知必会》不仅介绍了简单的查询语句,还深入介绍了复杂的SQL查询和数据连接操作,例如多表查询、子查询、联合查询和数据排序等。此外,书中还介绍了SQL的数据过滤、数据修改和数据删除等操作,帮助读者实现对数据库的灵活操作。 此外,《SQL必知必会》还介绍了SQL函数的使用和常见的数据类型,如日期、字符串和数字等。通过学习这些知识,读者可以更好地理解和操作数据库。书中还介绍了常见的数据库管理系统,如MySQL、Oracle和SQL Server,并讲解了它们之间的差异和特点。 总的来说,《SQL必知必会》是一本很好的SQL入门教材。它的编写方式简单易懂,且内容详实全面,能够帮助读者快速理解和掌握SQL语言的基本概念和操作技巧。无论是初学者还是有一定SQL基础的读者,都能够从中受益匪浅。如果你希望提升你的SQL技能,这本书是一个很好的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值