前端 MySQL 入门 (中)

108 阅读24分钟

前言

    此篇为MySql 入门中篇,共十章,绝大部分内容来自《Mysql 必知必会》这本书,文末有其余内容链接

十一、使用 数据处理函数

11.1 函数

与其他大多数计算机语言一样,SQL支持利用函数来处理数据。函数 一般是在数据上执行的,它给数据的转换和处理提供了方便。

11.2 使用函数

大多数SQL支持以下四类函数

  • 用于处理文本字符串(如删除或填充值,转换值为大写或小写)的文本函数
  • 用于在数值数据上进行算术操作(如返回绝对值,进行代数运算) 的数值函数。
  • 用于处理日期和时间值并从这些值中提取特定成分(例如,返回 两个日期之差,检查日期有效性等)的日期和时间函数。
  • 返回DBMS正使用的特殊信息(如返回用户登录信息,检查版本 细节)的系统函数。

11.2.1 文本函数

SELECT pro_name, Upper(pro_name) AS upperName FROM products WHERE pro_price > 24;

常用文本处理函数
函数说明
Left()/Right()返回字符左边/右边的几个字符
Length()返回串的长度
Locate()找出字符串中的一个子串
Lower()/Upper()将串转换为小/大写
RTrim()/LTrim()去掉左/右边空格
Soundex()返回串的SOUNDEX值
SubString()SubString() 返回子串的字符

Substring('原字符串', 起始index, 终止index);

Left(‘原始字符’, 字符数量);

Locate('要搜索的串', '被搜索的母串', [搜索位置 默认是1]);

SOUNDEX() 是一个字符串函数,在某些数据库系统中可用,用于生成字符串的音标码(phonetic code)。音标码是一种用于比较发音相似性的编码方式。

函数返回 'O150',这是 'OpenAI' 的音标码。

11.2.2 日期和时间处理函数

应该总是使用4位数字的年份。日期必须为 格式yyyy-mm-dd。

虽然其他的 日期格式可能也行,但这是首选的日期格式,因为它排除了多义性(如, 04/05/06是2006年5月4日或2006年4月5日或2004年5月6日或……)。

好的习惯: 使用Date() 函数,仅提取列的日期部分,哪怕当前列信息只存了yyyy-mm-dd,保不齐什么时候加上时间,如果确定是比较日期,那加上Date()函数会更靠谱

使用BETWEEN匹配日期范围

使用日期函数匹配日期范围(不需要考虑是否是闰月)

11.2.3 数值处理函数

十二、汇总数据

12.1 聚集函数

12.1.1 AVG()函数

SELECT AVG(pro_price) AS avg_price FROM products;

12.1.2 COUNT()函数

SELECT COUNT(pro_price) AS total_count FROM products;

COUNT()函数有两种使用方式:

  • 使用COUNT(*) 对表中的数目进行计数,不管表列中包含的是空值(NULL)还是非空值
  • 使用COUNT(column) 计数,忽略NULL值

12.1.3 MAX() 函数

SELECT MAX(pro_price) AS avg_price FROM products;

12.1.4 MIN() 函数

SELECT MIN(pro_price) AS avg_price FROM products;

12.1.5 SUM()函数

SELECT SUM(pro_price) AS avg_price FROM products;

12.2 聚集不同值

说明:
1、以上5个函数都可以使用 DISTINCT

2、以上函数默认指定 “ALL” 参数

3、DISTINCT 用于MAX和MIN():从技术上可以,但是没有实际意义

SELECT COUNT(DISTINCT pro_price) AS total_count FROM products;

// 在COUNT函数里使用 DISTINCT 必须使用列名,不能用于COUNT(*)

12.3 组合聚集函数

多个聚集函数一起使用

SELECT SUM(pro_price) AS avg_price, AVG(pro_price) AS avg_price, COUNT(pro_price) AS count FROM products;

十三、分组数据

分组允许把数据分成多个逻辑组,以便对能对每个组进行聚集计算。

13.1 创建分组

SELECT vend_id, COUNT(*) AS num_prods FROM products GROUP BY vend_id;

使用GROUP BY的一些规定:

  • GROUP BY子句可以包含任意数目的列。这使得能对分组进行嵌套, 为数据分组提供更细致的控制。
  • 如果在GROUP BY子句中嵌套了分组,数据将在最后规定的分组上 进行汇总。换句话说,在建立分组时,指定的所有列都一起计算 (所以不能从个别的列取回数据)。
  • GROUP BY子句中列出的每个列都必须是检索列或有效的表达式 (但不能是聚集函数)。如果在SELECT中使用表达式,则必须在 GROUP BY子句中指定相同的表达式。不能使用别名。
  • 除聚集计算语句外,SELECT语句中的每个列都必须在GROUP BY子 句中给出。 
  • 如果分组列中具有NULL值,则NULL将作为一个分组返回。如果列 中有多行NULL值,它们将分为一组。 
  • GROUP BY子句必须出现在WHERE子句之后,ORDER BY子句之前。

WITH ROLLUP 关键字,得到每个列的汇总值

13.2 过滤分组

HAVING子句,HAVING子句非常类似于WHERE,HAVING支持所有WHERE操作符。区别就是HAVING过滤分组,而WHERE过滤行。

SELECT vend_id, COUNT(*) AS num_prods FROM products GROUP BY vend_id HAVING num_prods > 3;

13.3 分组和排序

虽然GROUP BY 和 ORDER BY 经常完成相同的工作,但是他们是非常不同的,下图是区别

不要忘记ORDER BY :一般在使用GROUP BY子句时,应该也给出ORDER BY 子句。这是保证数据正确排序的唯一方法。千万不要仅依赖GROUP BY 排序数据

13.4 SELECT 子句顺序

子句说明是否必须使用
SELECT要返回的列或表达式
FROM从中检索数据的表仅在从表选择数据时使用
WHERE行级过滤
GROUP BY分组说明仅在按组计算聚集时使用
ORDER BY输出排序顺序
HAVING组级过滤
LIMIT要检索的行数

十四、使用子查询

14.1 子查询

SQL允许创建子查询,即嵌套在其他查询中查询。

14.2 利用子查询进行过滤

前提:有三张表。

目标:要列出订购物品TNT2的所有客户

1、vendors表

vendors表存储销售产品的供应商。每个供应商在这个表中有一个记 录,供应商ID(vend_id)列用来匹配产品和供应商。

2、products表

products表包含产品目录,每行一个产品。每个产品有唯一的ID (prod_id列),通过vend_id(供应商的唯一ID)关联到它的供应商。

3、customers表
customers表存储所有顾客的信息。每个顾客有唯一的ID(cust_id 列)。

步骤:

(1) 检索包含物品TNT2的所有订单的编号。

(2) 检索具有前一步骤列出的订单编号的所有客户的ID。

(3) 检索前一步骤返回的所有客户ID的客户信息。

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 ='TNT2'));
// 最里边的查询返回订单号列表
// 中间子查询返回客户ID列表

// 最外层查询返回所需的客户信息

列必须匹配:在WHERE语句中使用子查询,应该保证SELECT语句具有与WHERE子句相同数目的列(第一个WHERE里的cust_id; 第二个WHERE里的 order_num)。

通常,子查询返回单个列并且与单个列匹配,但也可以使用多个列。

通常,子查询结合IN使用,但也可以用 (=)、(<>)等

14.3 作为计算字段使用子查询

创建计算字段是使用子查询的另外一种方法。比如要查customs表中的每个客户的订单总数。

订单与相应的客户ID是在orders表中的

SELECT cust_name, 
(SELECT COUNT(*) FROM orders WHERE customers.cust_id = orders.cust_id) AS orders
FROM customers ORDER BY cust_name;

// 括号中使用了完全限定列名,为了区分两个表

逐渐增加子查询来建立查询:用子查询建立(和测试)查询的最可靠的方式是逐渐进行。
首先,建立和测试最内层查询,然后用硬编码数据建立和测试外层查询,确保每一步的正确

十五、联结表

15.1 联结(join)

SQL最强大的功能之一就是能在数据检索查询的执行中执行联结(join)

15.1.1 关系表

关系表设计的初衷就是解决数据重复出现问题。关系表的设计就是保证把信息分解成多个表,一类数据一个表。各表通过某些常用的值(即关系表中的关系)相关联。

  • 外键 外键为某个表中的一列,它包含另一个表的主键值,定义了两个表之间的关系
  • 可伸缩性 能够适应不断增加的工作量而不失败。设计良好的数据库或应用程序称之为可伸缩性好

15.1.2 为什么要使用联结

如果想要的数据存储多个表中,怎样用单条SELECT语句检索出数据?

答案是用联结。联结是一种机制,用来在一条SELECT语句中关联表,因此称为联结

15.2 创建联结

SELECT vend_name, pro_name, pro_price FROM vendors, products
WHERE vendors.vend_id = products.vend_id
ORDER BY vend_name, pro_name

如果没有WHERE语句,即由没有联结条件的表关系返回的结果叫 笛卡儿积,也叫叉联结(cross join)

15.2.1 内部联结

目前为止所用的联结称为 等值联结, 它基于两个表之间的相等测试,这种联结也称为内部联结。是最常用的联结形式。

使用 INNER JOIN:

SELECT vend_name, pro_name, pro_price FROM vendors INNER JOIN products
ON vendors.vend_id = products.vend_id;
// FROM语句中,以 INNER JOIN 指定两个表的关系,联结条件用特定的 ON 关键字。
// 首选 INNER JOINT 写法,性能较WHERE要好

15.2.3 联结多个表

SELECT pro_name, vend_name, pro_price, quantity
FROM orderitems, products, vendors
WHERE products.vend_id = vendors.vend_id
AND ordersitems.pro_id = products.pro_id
AND order_num = 20005;

不要联结不必要的表,联结的越多,性能下降的越厉害

改写之前嵌套子查询的写法:

SELECT cust_name, cust_concat
FROM customs, orders, orderitems
WHERE customs.cust_id = orders.cust_id
AND orderitems.order_num = orders.order_num
AND prod_id = 'TNT2';

多做实验:为执行一给定量的SQL操作,一般存在不止一种方法。很少有绝对正确或者绝对错误的方法。性能可能会受操作类型、表中数据量、是否存在索引或键以及其他一些条件的影响。

十六、创建高级联结

16.1 使用表别名

SQL允许给表起别名,有两个好处:

  • 缩短SQL 语句
  • 能在单条SELECT语句中多次使用相同的表

例子:

SELECT cust_name, cust_concat
FROM customs AS c, orders AS O, orderitems AS oi
WHERE oi.cust_id = o.cust_id
AND oi.order_num = o.order_num
AND prod_id = 'TNT2';

16.2 使用不同类型的联结

除了内部联结(或等值联结)还有其他三种联结,分别是自联结、自然联结和外部联结。

16.2.1 自联结

假如你发现某物品(其ID为DTNTR)存在问题,因此想知道生产该物 品的供应商生产的其他物品是否也存在这些问题。此查询要求首先找到 生产ID为DTNTR的物品的供应商,然后找出这个供应商生产的其他物品。

可以使用子查询:

SELECT prod_id, prod_name
FROM products
WHERE vend_id = (SELECT vend_id FROM prod_id = 'DTNTER');

使用联结的相同查询

SELECT p1.prod_id, p1.prod_name
FROM products AS p1, products AS p2
WHERE p1.vend_id = p2.vend_id
AND p2.prod_id = 'DTNTER';

自联结: 自联结通常作为外部语句用来替代从相同的表中检索数据时使用的子查询语句。

16.2.2 自然联结

无论何时对表进行联结,应该至少有一个列出现在不止一个表中(被 联结的列)。标准的联结(前一章中介绍的内部联结)返回所有数据,甚至相同的列多次出现。自然联结排除多次出现,使每个列只返回一次。

SELECT c.*, o.order_num, o.order_date,
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 = 'FB'
// 对第一个表使用了通配符

简单理解:自然联结就是没有重复的列被检索出来

16.2.3 外部联结

使用 LEFT 或 RIGHT 关键字指定包括所有行的表,再加上 OUTER JOIN

例子:检索所有用户,包括没有订单的客户

SELECT customs.cuts_id, orders.order_num
FROM customs LEFT OUTER JOIN orders
ON customs.cust_id = orders.cust_id;

LEFT OUTER JOIN 和 RIGHT OUTER JOIN 之间的差异仅在于返回结果中保留哪个表的所有记录。左外连接返回左表(OURER JOIN的左边的表)的所有记录,右外连接返回右表的所有记录。

16.3 使用带聚合函数的联结

此SELECT语句使用INNER JOIN将customers和orders表互相关联。 GROUP BY 子句按客户分组数据,因此,函数调用 COUNT (orders.order_num)对每个客户的订单计数,将它作为num_ord返回。

也可以与其他联结一起使用:

16.4 使用联结和联结条件

关于联结及其使用的 某些要点。

  • 注意所使用的联结类型。一般我们使用内部联结,但使用外部联 结也是有效的。 
  • 保证使用正确的联结条件,否则将返回不正确的数据。
  • 应该总是提供联结条件,否则会得出笛卡儿积。
  • 在一个联结中可以包含多个表,甚至对于每个联结可以采用不同 的联结类型。虽然这样做是合法的,一般也很有用,但应该在一 起测试它们前,分别测试每个联结。这将使故障排除更为简单。

十七、组合查询

17.1 组合查询

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

需要使用组合查询:

  • 在单个查询中从不同的表返回类似结构的数据;
  • 对单个表执行多个查询,按单个查询返回数据。

17.2 创建组合查询

利用UNION,可给出多条SELECT语句,将它们的结果组合成单个结果集。

17.2.1 使用UNION

创建UNION涉及编写多条SELECT语句。

举一个例子,假如需要价格小于等于5的所有物品的一个列表,而且 还想包括供应商1001和1002生产的所有物品(不考虑价格)

SELECT vend_id, prod_id, prod_price
FROM products
WHERE prod_price <= 5
UNION
SELECT vend_id, prod_id, prod_price
FROM products
WHERE vend id IN (1001,1002);

UNION指示MySQL执行两条SELECT语句,并把输出组 合成单个查询结果集。

如果改成用 WHERE 写:

SELECT vend_id, prod_id, prod price
FROM products
WHERE prod_price <= 5
OR vend_id IN (1001,1002);

在这个简单的例子中,使用UNION可能比使用WHERE子句更为复杂。 但对于更复杂的过滤条件,或者从多个表(而不是单个表)中检索数据 的情形,使用UNION可能会使处理更简单。

17.2.2 UNION规则

  • UNION必须由两条或两条以上的SELECT语句组成,语句之间用关 键字UNION分隔(因此,如果组合4条SELECT语句,将要使用3个 UNION关键字)
  • UNION中的每个查询必须包含相同的列、表达式或聚集函数(不过各个列不需要以相同的次序列出)。
  • 列数据类型必须兼容:类型不必完全相同,但必须是DBMS可以 隐含地转换的类型(例如,不同的数值类型或不同的日期类型)。

17.2.3 是否去掉重复行

UNION 默认去掉重复的行,如果不去重,可以使用 UNION ALL

SELECT vend_id, prod_id, prod_price
FROM products
WHERE prod_price
<= 5
UNION ALL
SELECT vend id, prodid, prod_price
FROM products
WHERE vend_id IN (1001, 1002);

UNION与WHERE:本章开始时说过,UNION几乎总是完成与多个 WHERE条件相同的工作。UNION ALL为UNION的一种形式,它完成 WHERE子句完成不了的工作。如果确实需要每个条件的匹配行全 部出现(包括重复行),则必须使用UNION ALL而不是WHERE

17.2.4 对组合查询结果排序

SELECT语句的输出用ORDER BY子句排序。在用UNION组合查询时,只能使用一条ORDER BY子句,它必须出现在最后一条SELECT语句之后。对于结果集,不存在用一种方式排序一部分,而又用另一种方式排序另一 部分的情况,因此不允许使用多条ORDER BY子句。

十八、全文本搜索

18.1 理解全文本搜索

MySQL提供了全文本搜索(Full-Text Search)的功能,允许在文本数据中执行高级的关键词搜索。MySQL的全文本搜索是一种内置的搜索引擎(两个最常使用的引擎为MyISAM和InnoDB, 前者支持全文本搜索,而后者不支持),可以用于查询包含文本的列,如VARCHAR、TEXT和CHAR等

18.2 使用全文本搜索

18.2.1 创建全文本搜索

在定义之后,MySQL自动维护该索引。在增加、更新或删除行时, 索引随之自动更新。

如果上面的表已经存在,可以使用下面的语句:

ALTER TABLE productnotes ADD FULLTEXT (note_text)

不要在导入数据时使用FULLTEXT 更新索引要花时间,虽然不是很多,但毕竟要花时间。如果正在导入数据到一个新表, 此时不应该启用FULLTEXT索引。应该首先导入所有数据,然后再修改表,定义FULLTEXT。这样有助于更快地导入数据(而且使索引数据的总时间小于在导入每行时分别进行索引所需 的总时间)。

18.2.2 进行全文本搜索

使用两个函数Match()和Against()执行全文本搜索:

SELECT * FROM productnotes Match(note_text) Against('rabbit')

1、使用完整的 Match() 说明: 传递给 Match() 的值必须与 FULLTEXT()定义中的相同。如果指定多个列,则必须列出它们(而且次序正确)。

2、搜索不区分大小写: 除非使用BINARY方式(本章中没有介绍), 否则全文本搜索不区分大小写。

举一个例子:

初始数据:

搜索只包括‘CustomerF’的:

搜索包含‘customer’的:

写错单词试一下:

总结:
1、Against 中的匹配是各个单词(token)的精确匹配

2、默认不区分大小写

18.2.3 使用查询扩展

查询扩展用来设法放宽所返回的全文本搜索结果的范围。在使用查询扩展时,MySQL对数据和 索引进行两遍扫描来完成搜索:

  • 首先,进行一个基本的全文本搜索,找出与搜索条件匹配的所有行;
  • 其次,MySQL检查这些匹配行并选择所有有用的词;
  • 再其次,MySQL再次进行全文本搜索,这次不仅使用原来的条件, 而且还使用所有有用的词。
SELECT note_text FROM productnotes WHERE Match(note_text) Against('rabbit') WITH QUERY EXPANSION

通过使用WITH QUERY EXPANSION,MySQL将自动扩展搜索查询,以便包括与查询相关的词汇,从而提供更全面的搜索结果。这有助于扩展查询范围,以便更好地覆盖相关的文本内容。

需要注意的是,WITH QUERY EXPANSION的具体行为取决于MySQL的配置和全文本搜索索引的设置。您可以通过调整MySQL的全文本搜索配置参数,如ft_min_word_len和ft_query_expansion_limit,来自定义WITH QUERY EXPANSION的行为和结果。

执行会报错:

 SELECT * FROM orders WHERE Match(customer_name, comment) Against('customer') WITH QUERY EXPANSION;
//  You have an error in your SQL syntax; check the manual that corresponds to
//  your MySQL server version for the right syntax to use near
// 'WITH QUERY EXPANSION' at line 1

18.2.4 布尔文本搜索

MySQL支持全文本搜索的另外一种形式,称为布尔方式。语法是在 Against 内部后面加上 IN
BOOLEAN MODE。

例子 1:排除 ‘heavy’


例子 2:必须包含 ‘heavy’:

18.2.5 全文本搜索说明

  • 在索引全文本数据时,短词被忽略且从索引中排除。短词定义为 那些具有3个或3个以下字符的词(如果需要,这个数目可以更改)。 
  • MySQL带有一个内建的非用词(stopword)列表,这些词在索引全文本数据时总是被忽略。如果需要,可以覆盖这个列表(请参 阅MySQL文档以了解如何完成此工作)。
  • 许多词出现的频率很高,搜索它们没有用处(返回太多的结果)。 因此,MySQL规定了一条50%规则,如果一个词出现在50%以上 的行中,则将它作为一个非用词忽略。50%规则不用于IN BOOLEAN MODE。
  • 如果表中的行数少于3行,则全文本搜索不返回结果(因为每个词 或者不出现,或者至少出现在50%的行中)。 
  • 忽略词中的单引号。例如,don't索引为dont。 
  • 不具有词分隔符(包括日语和汉语)的语言不能恰当地返回全文 本搜索结果。
  • 仅在MyISAM数据库引擎中支持全文本搜索。

十九、插入数据

19.1 数据插入

INSERT是用来插入(或添加)行到数据库表的。插入可 以用几种方式使用:

  • 插入完整的行;
  • 插入行的一部分;
  • 插入多行;
  • 插入某些查询的结果。

19.2 插入完整的行

INSERT INTO orders VALUES(NULL, '2023-06-27', 'tom', '400');

虽然这种语法很简单,但并不安全,应该尽量避免使用。上面的SQL 语句高度依赖于表中列的定义次序,并且还依赖于其次序容易获得的信 息。即使可得到这种次序信息,也不能保证下一次表结构变动后各个列 保持完全相同的次序。因此,编写依赖于特定列次序的SQL语句是很不安 全的。

INSERT INTO orders(order_id, order_date, customer_name, total_amount) VALUES(NULL, '2023-06-27', 'tom', '400');

不管使用哪种INSERT语法,都必须给出 VALUES的正确数目。如果不提供列名,则必须给每个表列提供 一个值。如果提供列名,则必须对每个列出的列给出一个值。 如果不这样,将产生一条错误消息,相应的行插入不成功。

省略列 如果表的定义允许,则可以在INSERT操作中省略某 些列。省略的列必须满足以下某个条件。  该列定义为允许NULL值(无值或空值)。  在表定义中给出默认值。这表示如果不给出值,将使用默 认值。 如果对表中不允许NULL值且没有默认值的列不给出值,则 MySQL将产生一条错误消息,并且相应的行插入不成功。

提高整体性能 数据库经常被多个客户访问,对处理什么请 求以及用什么次序处理进行管理是MySQL的任务。INSERT操 作可能很耗时(特别是有很多索引需要更新时),而且它可能 降低等待处理的SELECT语句的性能。 如果数据检索是最重要的(通常是这样),则你可以通过在 INSERT和INTO之间添加关键字LOW_PRIORITY,指示MySQL 降低INSERT语句的优先级,如下所示: 顺便说一下,这也适用于下一章介绍的UPDATE和DELETE语句。

19.3 插入多个行

可以使用多条INSERT语句,甚至一次提交它们,每条语句用一个分号结束

INSERT INTO orders(order_id, 
order_date,
customer_name,
total_amount)
VALUES(NULL,
'2023-06-27',
'tom',
'400');

INSERT INTO orders(order_id, 
order_date,
customer_name,
total_amount)
VALUES(NULL,
'2023-06-28',
'jim',
'800');

或者,只要每条INSERT语句中的列名(和次序)相同,其中单条INSERT语句有多组值,每组值用一对圆括号括起来, 用逗号分隔。

INSERT INTO orders(order_id, 
order_date,
customer_name,
total_amount)

VALUES(NULL,
'2023-06-27',
'tom',
'400'),
(NULL,
'2023-06-28',
'jim',
'800');

19.4 插入检索出的数据

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:

这个例子使用INSERT SELECT从custnew中将所有数据导入 customers。

INSERT SELECT中的列名 为简单起见,这个例子在INSERT和 SELECT语句中使用了相同的列名。但是,不一定要求列名匹配。 事实上,MySQL甚至不关心SELECT返回的列名。它使用的是 列的位置,因此SELECT中的第一列(不管其列名)将用来填充 表列中指定的第一个列,第二列将用来填充表列中指定的第二 个列,如此等等。这对于从使用不同列名的表中导入数据是非 常有用的。

二十、更新和删除数据

20.1 更新数据

UPDATE 语句有两种更新方式:

  • 更新表中特定的行
  • 更新表中所有的行

UPDATE语句由三部分组成:

  • 要更新的表
  • 列名和他们的新值
  • 确定要更新行的过滤条件
UPDATE customers
SET cust_email = 'elemer@fff.com'
WHERE cust_id = 10086;

UPDATE语句以WHERE子句结束,没有 WHERE子句,MySQL将会更新表中所有电子邮箱地址

UPDATE customers
SET cust_email = 'elemer@fff.com',
    cust_name = 'alibaba'
WHERE cust_id = 10086;
// 在更新多个列时,只需要使用单个SET命令,每个“列=值”对之间
// 用逗号分隔(最后一列之后不用逗号)。

1、在UPDATE语句中使用子查询:

UPDATE语句中可以使用子查 询,使得能用SELECT语句检索出的数据更新列数据。

2、IGNORE 关键字:

如果使用 UPDATE 语句更新多行,其中出现错误的时候,默认整个 UPDATE操作都被取消,如果想在发生错误时,也继续执行更新,可使用 IGNORE

UPDATE IGNORE customers

删除某个列的值,可 set 为 NULL

UPDATE customers 
SET cust_email = NULL
WHERE cust_id = 10086;

20.2 删除数据

两种方式删除数据:

  • 删除特定行
  • 删除所有行
DELETE FROM customers
WHERE cust_id = 10086;

1、删除表的内容而不是表:

DELETE语句从表中删除行,甚至是 删除表中所有行。但是,DELETE不删除表本身。

可以看到,表为空,但是还存在

2、更快的删除:TRUNCATE TABLE 表名

如果想从表中删除所有行,不要使用DELETE。 可使用TRUNCATE TABLE语句,它完成相同的工作,但速度更快。 TRUNCATE TABLE是一个MySQL语句,用于快速清空数据库表中的所有数据,同时保留表的结构、索引和约束。

使用TRUNCATE TABLE时要注意以下几点:

  1. TRUNCATE TABLE将删除表中的所有数据,但不会删除表本身。
  2. TRUNCATE TABLE操作比DELETE操作更快,因为它是直接删除数据页而不是逐行删除。
  3. TRUNCATE TABLE将重置自增长列的计数器(如果有的话),下一次插入数据时将从1开始计数。
  4. TRUNCATE TABLE不会触发触发器,也不会记录在MySQL的二进制日志中(除非启用了特殊的日志记录设置)。

20.3 更新和删除的指导原则

下面是许多SQL程序员使用UPDATE或DELETE时所遵循的习惯。

  • 除非确实打算更新和删除每一行,否则绝对不要使用不带WHERE 子句的UPDATE或DELETE语句。
  • 保证每个表都有主键(如果忘记这个内容,请参阅第15章),尽可能 像WHERE子句那样使用它(可以指定各主键、多个值或值的范围)。
  • 在对UPDATE或DELETE语句使用WHERE子句前,应该先用SELECT进 行测试,保证它过滤的是正确的记录,以防编写的WHERE子句不 正确。
  • 使用强制实施引用完整性的数据库(关于这个内容,请参阅第15 章),这样MySQL将不允许删除具有与其他表相关联的数据的行。

小心使用 MySQL没有撤销(undo)按钮。应该非常小心地 使用UPDATE和DELETE

篇幅所限,其余内容在这里: