【笔记】Mysql 必知必会

快速过完这本书..... 只记了些容易忘或者不太熟悉的点

第二章 MySQL简介

MySQL版本主要修改

4 InnoDB引擎,增加事务处理(第26章)、并(第17章)、改 进全文本搜索(第18章)等的支持。
4.1 对函数库、子查询(第14章)、集成帮助等的重要增加。
5 存储过程(第23章)、触发器(第25章)、游标(第24章)、
视图(第22章)等

第四章 检索数据

SQL语句和大小写 请注意,SQL语句不区分大小写,因此 SELECT与select是相同的。同样,写成Select也没有关系。 许多SQL开发人员喜欢对所有SQL关键字使用大写,而对所有 列和表名使用小写,这样做使代码更易于阅读和调试。

检索不同的行

SELECT DISTINCT vend_id  

//告诉MySQL只返回不同(唯一)的 vend_id行 输出

*----------*
| vend_id |
|  1001   |
|  1002   |
|  1003   |
*----------*

不能部分使用DISTINCT DISTINCT关键字应用于所有列而 不仅是前置它的列。如果给出SELECT DISTINCT vend_id, prod_price,除非指定的两个列都不同,否则所有行都将被 检索出来。

第五章 排序

5.2 按多个列排序

select * from xxx order by prod_price, prod_name
仅在多个行具有相同的prod_price值时才对产品按prod_name进行排序。

区分大小写和排序顺序
在对文本性的数据进行排序时,A与a相同吗?a位于B之前还是位于Z之后?这些问题不是理论问 题,其答案取决于数据库如何设置。
在字典(dictionary)排序顺序中,A被视为与a相同,这是MySQL (和大多数数据库管理系统)的默认行为。但是,许多数据库 管理员能够在需要时改变这种行为(如果你的数据库包含大量
外语字符,可能必须这样做)。
这里,关键的问题是,如果确实需要改变这种排序顺序,用简 单的ORDER BY子句做不到。你必须请求数据库管理员的帮助。

第六章 过滤数据

6.2.4 空值检查

在创建表时,表设计人员可以指定其中的列是否可以不包含值。在
一个列不包含值时,称其为包含空值NULL。
SELECT语句有一个特殊的WHERE子句,可用来检查具有NULL值的列。
这个WHERE子句就是IS NULL子句。
select * from xxx where prod_price IS NULL

第八章 用通配符过滤

8.1.1 百分号(%)通配符

最常使用的通配符是百分号(%)。在搜索串中,%表示任何字符出现 任意次数。例如,为了找出所有以词jet起头的产品,可使用以下SELECT 语句:

SELECT * FROM products WHERE prod_name LIKE 'jet%'

此例子使用了搜索模式'jet%'。在执行这条子句时,将检索任
意以jet起头的词。%告诉MySQL接受jet之后的任意字符,不 管它有多少字符。

区分大小写 根据MySQL的配置方式,搜索可以是区分大小 写的。如果区分大小写,'jet%'与JetPack 1000将不匹配。

通配符可在搜索模式中任意位置使用,并且可以使用多个通配符。 下面的例子使用两个通配符,它们位于模式的两端:

SELECT * FROM products WHERE prod_name LIKE '%jet%'

注意尾空格
尾空格可能会干扰通配符匹配。例如,在保存词 anvil时,如果它后面有一个或多个空格,则子句WHERE prod_name LIKE '%anvil'将不会匹配它们,因为在最后的l 后有多余的字符。解决这个问题的一个简单的办法是在搜索模 式最后附加一个%。一个更好的办法是使用函数(第11章将会 介绍)去掉首尾空格。

注意NULL
虽然似乎%通配符可以匹配任何东西,但有一个例 外,即NULL。即使是WHERE prod_name LIKE '%'也不能匹配 用值NULL作为产品名的行。

8.1.2 下划线(_)通配符

另一个有用的通配符是下划线()。下划线的用途与%一样,但下划
线只匹配单个字符而不是多个字符。
与%能匹配0个字符不一样,
总是匹配一个字符,不能多也不能少。

8.2 使用通配符的技巧

正如所见,MySQL的通配符很有用。但这种功能是有代价的:通配 符搜索的处理一般要比前面讨论的其他搜索所花时间更长。这里给出一 些使用通配符要记住的技巧。

  • 不要过度使用通配符。如果其他操作符能达到相同的目的,应该 使用其他操作符。
  • 在确实需要使用通配符时,除非绝对有必要,否则不要把它们用 在搜索模式的开始处。把通配符置于搜索模式的开始处,搜索起 来是最慢的。
  • 仔细注意通配符的位置。如果放错地方,可能不会返回想要的数据

第九章 用正则表达式 进行搜索

仅为正则表达式语言的一个子集 如果你熟悉正则表达式,需 要注意:MySQL仅支持多数正则表达式实现的一个很小的子 集。本章介绍MySQL支持的大多数内容。

9.2.1 基本字符匹配

SELECT * FROM product WHERE product_name REGEXP '1000'
除关键字LIKE被REGEXP替代外,这条语句看上去非常像使用
LIKE的语句(第8章)。它告诉MySQL:REGEXP后所跟的东西作 为正则表达式(与文字正文1000匹配的一个正则表达式)处理。

*----------*
| product_name |
|  JetPack 1000   |
*----------*

支持操作符

. 
|
[]
[1-5]
\\  (转义,比如查找. 需要\\.)

9.2.6 匹配字符类

说明
[:alnum:] 任意字母和数字(同[a-zA-Z0-9])
[:alpha:] 任意字符(同[a-zA-Z])
[:blank:] 空格和制表(同[\t])
[:cntrl:] ASCII控制字符(ASCII 0到31和127)
[:digit:] 任意数字(同[0-9])
[:graph:] 与[:print:]相同,但不包括空格
[:lower:] 任意小写字母(同[a-z])
[:print:] 任意可打印字符
[:punct:] 既不在[:alnum:]又不在[:cntrl:]中的任意字符
[:space:] 包括空格在内的任意空白字符(同[\f\n\r\t\v])
[:upper:] 任意大写字母(同[A-Z])
[:xdigit:] 任意十六进制数字(同[a-fA-F0-9])

第十章、创建计算字段

10.2 拼接字段

vendors表包含供应商名和位置信息。假如要生成一个供应商报表, 需要在供应商的名字中按照name(location)这样的格式列出供应商的位置。
此报表需要单个值,而表中数据存储在两个列vend_name和vend_ country中。此外,需要用括号将vend_country括起来,这些东西都没有 明确存储在数据库表中。我们来看看怎样编写返回供应商名和位置的 SELECT语句。

SELECT Concat(vend_name, ' (', vend_country, ') ') FROM vendor;

此外还可以叠加去空格

SELECT Concat(RTrim(vend_name), ' (', vend_country, ') ') FROM vendor;

RTrim()函数去掉值右边的所有空格。通过使用RTrim(),各个 列都进行了整理。

Trim函数 MySQL除了支持RTrim()(正如刚才所见,它去掉 串右边的空格),还支持LTrim()(去掉串左边的空格)以及 Trim()(去掉串左右两边的空格)。

使用别名
别名用AS关键字赋予

SELECT Concat(RTrim(vend_name), ' (', vend_country, ') ') as vend_title FROM vendor;

10.3 使用算数运算

支持加减乘除 + — * /

第十一章 使用数据处理函数

函数没有SQL的可移植性强
能运行在多个系统上的代码称 为可移植的(portable)。相对来说,多数SQL语句是可移植的, 在SQL实现之间有差异时,这些差异通常不那么难处理。而函 数的可移植性却不强。几乎每种主要的DBMS的实现都支持其 他实现不支持的函数,而且有时差异还很大。
为了代码的可移植,许多SQL程序员不赞成使用特殊实现的功 能。虽然这样做很有好处,但不总是利于应用程序的性能。如 果不使用这些函数,编写某些应用程序代码会很艰难。必须利 用其他方法来实现DBMS非常有效地完成的工作。
如果你决定使用函数,应该保证做好代码注释,以便以后你(或 其他人)能确切地知道所编写SQL代码的含义。

常用文本处理函数

Left() 返回串左边的字符
Length() 返回串的长度
Locate() 找出串的一个子串
Lower() 将串转换为小写
LTrim() 去掉串左边的空格
Right() 返回串右边的字符
RTrim() 去掉串右边的空格
Soundex() 返回串的SOUNDEX值
SubString() 返回子串的字符
Upper() 将串转换为大写

SOUNDEX 是一个将任何文 本串转换为描述其语音表示的字母数字模式的算法。SOUNDEX考虑了类似 的发音字符和音节,使得能对串进行发音比较而不是字母比较。虽然 SOUNDEX不是SQL概念,但MySQL(就像多数DBMS一样)都提供对 SOUNDEX的支持。

下面给出一个使用Soundex()函数的例子。customers表中有一个顾 客Coyote Inc.,其联系名为Y.Lee。但如果这是输入错误,此联系名实 际应该是Y.Lie,怎么办?显然,按正确的联系名搜索不会返回数据
现在试一下使用Soundex()函数进行搜索,它匹配所有发音类似于 Y.Lie的联系名:

SELECT * FROM customers WHERE Soundex(cust_contact) = Soundex('Y Lie');

11.2.2 日期和时间处理函数

AddDate() 增加一个日期(天、周等)
AddTime() 增加一个时间(时、分等)
CurDate() 返回当前日期
CurTime() 返回当前时间
Date() 返回日期时间的日期部分
DateDiff() 计算两个日期之差
Date_Add() 高度灵活的日期运算函数
Date_Format() 返回一个格式化的日期或时间串
Day() 返回一个日期的天数部分
DayOfWeek() 对于一个日期,返回对应的星期几
Hour() 返回一个时间的小时部分
Minute() 返回一个时间的分钟部分
Month() 返回一个日期的月份部分
Now() 返回当前日期和时间
Second() 返回一个时间的秒部分
Time() 返回一个日期时间的时间部分
Year() 返回一个日期的年份部分

首先需要注意的是MySQL使用的日期格式。无论你什么时候指定一个日期,不管是插入或更新表值还是用WHERE子句进行过滤,日期必须为 格式yyyy-mm-dd
因此,2005年9月1日,给出为2005-09-01。虽然其他的日期格式可能也行,但这是首选的日期格式,因为它排除了多义性(如, 04/05/06是2006年5月4日或2006年4月5日或2004年5月6日或......)

使用WHERE order_date = '2005-09-01'可靠吗?
order_date的数据类型为datetime,存储日期及时间值。
实际中比如,存储的order_date值为 2005-09-01 11:30:05,则WHERE order_date = '2005-09-01'失败。

解决办法是指示MySQL仅将给出的日期与列中的日期部分进行比 较,而不是将给出的日期与整个列值进行比较。
为此,必须使用Date() 函数。Date(order_date) 指示MySQL仅提取列的日期部分

如果要的是日期,请使用Date()
如果你想要的仅是日期, 则使用Date()是一个良好的习惯,即使你知道相应的列只包 含日期也是如此。这样,如果由于某种原因表中以后有日期和 时间值,你的SQL代码也不用改变。当然,也存在一个Time() 函数,在你只想要时间时应该使用它。
Date()和Time()都是在MySQL 4.1.1中第一次引入的

如果你想检索出2005年9月下的 所有订单,怎么办?

SELECT * FROM orders WHERE Year(order_date) = 2005 AND Month(order_date) = 9;

11.2.3 数值处理函数

Abs() 返回一个数的绝对值
Cos() 返回一个角度的余弦
Exp() 返回一个数的指数值
Mod() 返回除操作的余数
Pi() 返回圆周率
Rand() 返回一个随机数
Sin() 返回一个角度的正弦
Sqrt() 返回一个数的平方根
Tan() 返回一个角度的正切

第12章 汇总数据

SQL聚集函数
AVG() 返回某列的平均值
COUNT() 返回某列的行数
MAX() 返回某列的最大值
MIN() 返回某列的最小值
SUM() 返回某列值之和

12.1.2 COUNT()函数

COUNT()函数进行计数。可利用COUNT()确定表中行的数目或符合特
定条件的行的数目。 COUNT()函数有两种使用方式。

  1. 使用COUNT(*)对表中行的数目进行计数,不管表列中包含的是空 值(NULL)还是非空值。
  2. 使用COUNT(column)对特定列中具有值的行进行计数,忽略 NULL值

NULL值
如果指定列名,则指定列的值为空的行被COUNT() 函数忽略,但如果COUNT()函数中用的是星号(*),则不忽略。

12.1.3 MAX()函数

对非数值数据使用MAX()
虽然MAX()一般用来找出最大的数值或日期值,但MySQL允许将它用来返回任意列中的最大值,包括返回文本列中的最大值。
在用于文本数据时,如果数据按相应的列排序,则MAX()返回最后一行

NULL值
MAX()函数忽略列值为NULL的行。

12.1.4 MIN()函数

对非数值数据使用MIN()
MIN()函数与MAX()函数类似,MySQL允许将它用来返回任意列中的最小值,包括返回文本列中的最小值。在用于文本数据时,如果数据按相应的列排序,则MIN()返回最前面的行

NULL值
MIN()函数忽略列值为NULL的行。

12.2 聚集不同值

MySQL 5及后期版本
下面将要介绍的聚集函数的DISTINCT的使用,已经被添加到MySQL 5.0.3中。下面所述内容在MySQL 4.x中不能正常运行。

以上5个聚集函数都可以如下使用:

  • 对所有的行执行计算,指定ALL参数或不给参数(因为ALL是默认
    行为);
  • 只包含不同的值,指定DISTINCT参数。

ALL为默认
ALL参数不需要指定,因为它是默认行为。如果不指定DISTINCT,则假定为ALL。

下面的例子使用AVG()函数返回特定供应商提供的产品的平均价格。 它与上面的SELECT语句相同,但使用了DISTINCT参数,因此平均值只 考虑各个不同的价格:

SELECT AVG(DISTINCT prod_price) as avg_price FROM productsWHERE vendor_id=1003;

注意
如果指定列名,则DISTINCT只能用于COUNT()。
DISTINCT不能用于COUNT(*),因此不允许使用COUNT(DISTINCT), 否则会产生错误。类似地,DISTINCT必须使用列名,不能用于计算或表达式。

第13章 分组数据

在具体使用GROUP BY子句前,需要知道一些重要的规定。

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

13.3 过滤分组

HAVING和WHERE的差别
这里有另一种理解方法,WHERE在数据分组前进行过滤,HAVING在数据分组后进行过滤。这是一个重要的区别,WHERE排除的行不包括在分组中。这可能会改变计算值,从而影响HAVING子句中基于这些值过滤掉的分组。

13.4 分组和排序

虽然GROUP BY和ORDER BY经常完成相同的工作,但它们是非常不同
的。表13-1汇总了它们之间的差别。

ORDER BY GROUP BY
排序产生的输出 分组行。但输出可能不是分组的顺序
任意列都可以使用(甚至非选择的列也可以使用) 只可能使用选择列或表达式列,而且必须使用每个选择列表达式 )
不一定需要 如果与聚集函数一起使用列(或表达式),则必须使用

第14章 使用子查询

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

使用子查询的另一方法是创建计算字段。假如需要显示customers
表中每个客户的订单总数。订单与相应的客户ID存储在orders表中。 为了执行这个操作,遵循下面的步骤。
(1) 从customers表中检索客户列表。
(2) 对于检索出的每个客户,统计其在orders表中的订单数目。

正如前两章所述,可使用SELECT COUNT(*)对表中的行进行计数,并 且通过提供一条WHERE子句来过滤某个特定的客户ID,可仅对该客户的订单进行计数。例如,下面的代码对客户10001的订单进行计数:

SELECT COUNT(*) AS orders FROM orders WHERE cust_id=1001;

为了对每个客户执行COUNT(*)计算,应该将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表中每个客户返回3列:
cust_name、cust_state和orders。
orders是一个计算字段,它是由圆括号中的子查询建立的。该子查询对检索出的每个客户执行一次。在此例子中,该子查询执行了5次,因为检索出了5个客户。

子查询中的WHERE子句与前面使用的WHERE子句稍有不同,因为它使 用了完全限定列名(在第4章中首次提到)。下面的语句告诉SQL比较 orders表中的cust_id与当前正从customers表中检索的cust_id:
WHERE orders.cust_id = customers.cust_id

这种类型的子查询称为相关子查询。任何时候只要列名可能有多义 性,就必须使用这种语法(表名和列名由一个句点分隔)。

如果不完全限制列名

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

子查询会变成

SELECT COUNT(*) FROM orders WHERE cust_id = cust_id;

总是返回orders表中的订单总数(因为MySQL查看每个订单的cust_id 是否与本身匹配,当然,它们总是匹配的)

不止一种解决方案
正如本章前面所述,虽然这里给出的样 例代码运行良好,但它并不是解决这种数据检索的最有效的 方法。在后面的章节中我们还要遇到这个例子。

逐渐增加子查询来建立查询
用子查询测试和调试查询很有技巧性,特别是在这些语句的复杂性不断增加的情况下更是如此。用子查询建立(和测试)查询的最可靠的方法是逐渐进行, 这与MySQL处理它们的方法非常相同。首先,建立和测试最 内层的查询。然后,用硬编码数据建立和测试外层查询,并且仅在确认它正常后才嵌入子查询。这时,再次测试它。对于要 增加的每个查询,重复这些步骤。这样做仅给构造查询增加了 一点点时间,但节省了以后(找出查询为什么不正常)的大量 时间,并且极大地提高了查询一开始就正常工作的可能性。

第15章 链结表

关键是,相同数据出现多次决不是一件好事,此因素是关系数据库 设计的基础。关系表的设计就是要保证把信息分解成多个表,一类数据 一个表。各表通过某些常用的值(即关系设计中的关系(relational))互相关联。

products表只存储产品信息,它除了存储供应商ID(vendors表的主 键)外不存储其他供应商信息。vendors表的主键又叫作products的外键,它将vendors表与products表关联,利用供应商ID能从vendors表中找出相应供应商的详细信息。

维护引用完整性
重要的是,要理解联结不是物理实体。
换句话说,它在实际的数据库表中不存在。联结由MySQL根据需 要建立,它存在于查询的执行当中。
在使用关系表时,仅在关系列中插入合法的数据非常重要。
回到这里的例子,如果在products表中插入拥有非法供应商ID (即没有在vendors表中出现)的供应商生产的产品,则这些产品是不可访问的,因为它们没有关联到某个供应商。
为防止这种情况发生,可指示MySQL只允许在products表的 供应商ID列中出现合法值(即出现在vendors表中的供应商)。 这就是维护引用完整性,它是通过在表的定义中指定主键和外键来实现的。(这将在第21章介绍。)

15.2 创建联结

SELECT vend_name, 
       prod_name, 
       prod_price 
FROM venders, products 
WHERE venders.vend_id = products.vend_id 
ORDER BY vend_name, prod_name;

现在来看FROM子句
与以前的SELECT语句不一样,这条语句的FROM子句列出了两个表,分别是vendors和products。它们就是这条SELECT语句联结的两个表的名字。
这两个表用WHERE子句正确联结,WHERE子句指示MySQL匹配vendors表中的vend_id和products表中的vend_id。

15.2.1 WHERE子句的重要性

利用WHERE子句建立联结关系似乎有点奇怪,但实际上,有一个很充分的理由。
请记住,在一条SELECT语句中联结几个表时,相应的关系是在运行中构造的。在数据库表的定义中不存在能指示MySQL如何对表进行联结的东西。你必须自己做这件事情。
在联结两个表时,你实际上做的是将第一个表中的每一行与第二个表中的每一行配对。WHERE子句作为过滤条件,它只包含那些匹配给定条件(这里是联结条件)的行。
没有WHERE子句,第一个表中的每个行将与第二个表中的每个行配对,而不管它们逻辑上是否可以配在一起。

笛卡儿积(cartesian product)
由没有联结条件的表关系返回
的结果为笛卡儿积。检索出的行的数目将是第一个表中的行数乘 以第二个表中的行数

15.2.2 内部联结

目前为止所用的联结称为等值联结(equijoin),它基于两个表之间的 相等测试。这种联结也称为内部联结。其实,对于这种联结可以使用稍 微不同的语法来明确指定联结的类型。下面的SELECT语句返回与前面例 子完全相同的数据:

SELECT vend_name, 
       prod_name, 
       prod_price 
FROM venders, INNER JOIN products 
ON venders.vend_id = products.vend_id 
ORDER BY vend_name, prod_name;

此语句中的SELECT与前面的SELECT语句相同,但FROM子句不同。这里,两个表之间的关系是FROM子句的组成部分,以INNER JOIN指定。在使用这种语法时,联结条件用特定的ON子句而不是WHERE 子句给出。传递给ON的实际条件与传递给WHERE的相同。

使用哪种语法
ANSI SQL规范首选INNER JOIN语法。此外,尽管使用WHERE子句定义联结的确比较简单,但是使用明确的联结语法能够确保不会忘记联结条件,有时候这样做也能影响性能。

15.2.3 联结多个表

SQL对一条SELECT语句中可以联结的表的数目没有限制。创建联结
的基本规则也相同。首先列出所有表,然后定义表之间的关系。

第16章 创建高级联结

看看下面的区别

  1. 子查询
SELECT prod_id, prod_name 
FROM products
WHERE vend_id= (SELECT vend_id 
                from products
                WHERE prod_id='DTNTR')
  1. 自联结
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 = 'DTNTR'

用自联结而不用子查询
自联结通常作为外部语句用来替代从相同表中检索数据时使用的子查询语句。虽然最终的结果是相同的,但有时候处理联结远比处理子查询快得多。应该试一下两种方法,以确定哪一种的性能更好。

16.2.3 外部联结

许多联结将一个表中的行与另一个表中的行相关联。但有时候会需
要包含没有关联行的那些行。例如,可能需要使用联结来完成以下工作:

  • 对每个客户下了多少订单进行计数,包括那些至今尚未下订单的 客户;
  • 列出所有产品以及订购数量,包括没有人订购的产品;
  • 计算平均销售规模,包括那些至今尚未下订单的客户。

在上述例子中,联结包含了那些在相关表中没有关联行的行。这种 类型的联结称为外部联结。

在使用OUTER JOIN语法时,必须使用RIGHTLEFT关键字 指定包括其所有行的表(RIGHT指出的是OUTER JOIN右边的表,而LEFT 指出的是OUTER JOIN左边的表)

第17章 组合查询

17.1 组合查询

多数SQL查询都只包含从一个或多个表中返回数据的单条SELECT语 句。MySQL也允许执行多个查询(多条SELECT语句),并将结果作为单个 查询结果集返回。这些组合查询通常称为并(union)或复合查询
(compound query)。 有两种基本情况,其中需要使用组合查询:

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

组合查询和多个WHERE件
多数情况下,组合相同表的两个查询完成的工作与具有多个WHERE子句条件的单条查询完成的工作相同。换句话说,任何具有多个WHERE子句的SELECT语句都可以作为一个组合查询给出,在以下段落中可以看到这一点。 这两种技术在不同的查询中性能也不同。因此,应该试一下这 两种技术,以确定对特定的查询哪一种性能更好。

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)

第18章 全文本搜索

18.1 理解全文本搜索

并非所有引擎都支持全文本搜索
正如第21章所述,MySQL支持几种基本的数据库引擎。并非所有的引擎都支持本书所描 述的全文本搜索。两个最常使用的引擎为MyISAM和InnoDB, 前者支持全文本搜索,而后者不支持。这就是为什么虽然本书 中创建的多数样例表使用InnoDB,而有一个样例表(productnotes表)却使用MyISAM的原因。如果你的应用中需要全文本搜索功能,应该记住这一点。

18.2 使用全文本搜索

为了进行全文本搜索,必须索引被搜索的列,而且要随着数据的改 变不断地重新索引。在对表列进行适当设计后,MySQL会自动进行所有 的索引和重新索引。
在索引之后,SELECT可与Match()和Against()一起使用以实际执行 搜索。

第22章 视图

第23章 存储过程

迄今为止,使用的大多数SQL语句都是针对一个或多个表的单条语 句。并非所有操作都这么简单,经常会有一个完整的操作需要多条语句 才能完成。例如,考虑以下的情形。

  • 为了处理订单,需要核对以保证库存中有相应的物品。
  • 如果库存有物品,这些物品需要预定以便不将它们再卖给别的人,并且要减少可用的物品数量以反映正确的库存量。
  • 库存中没有的物品需要订购,这需要与供应商进行某种交互。
  • 关于哪些物品入库(并且可以立即发货)和哪些物品退订,需要通知相应的客户。

这显然不是一个完整的例子,它甚至超出了本书中所用样例表的范 围,但足以帮助表达我们的意思了。执行这个处理需要针对许多表的多条MySQL语句。此外,需要执行的具体语句及其次序也不是固定的,它们可能会(和将)根据哪些物品在库存中哪些不在而变化。

(不过这个存储过程我们一般在业务逻辑里处理)

23.2 使用存储过程的理由

优点
  • 通过把处理封装在容易使用的单元中,简化复杂的操作(正如前 面例子所述)。
  • 由于不要求反复建立一系列处理步骤,这保证了数据的完整性。 如果所有开发人员和应用程序都使用同一(试验和测试)存储过 程,则所使用的代码都是相同的。 这一点的延伸就是防止错误。需要执行的步骤越多,出错的可能 性就越大。防止错误保证了数据的一致性。
  • 简化对变动的管理。如果表名、列名或业务逻辑(或别的内容) 有变化,只需要更改存储过程的代码。使用它的人员甚至不需要 知道这些变化。
  • 提高性能。因为使用存储过程比使用单独的SQL语句要快。
  • 存在一些只能用在单个请求中的MySQL元素和特性,存储过程可 以使用它们来编写功能更强更灵活的代码(在下一章的例子中可
    以看到。)

换句话说,使用存储过程有3个主要的好处,即简单、安全、高性能。 显然,它们都很重要。不过,在将SQL代码转换为存储过程前,也必须知 道它的一些缺陷

缺点
  • 一般来说,存储过程的编写比基本SQL语句复杂,编写存储过程 需要更高的技能,更丰富的经验。
  • 你可能没有创建存储过程的安全访问权限。许多数据库管理员限 制存储过程的创建权限,允许用户使用存储过程,但不允许他们 创建存储过程。

第24章 游标

第25章 触发器

第26章 管理事务处理

并非所有引擎都支持事务处理
正如第21章所述,MySQL支持几种基本的数据库引擎。正如本章所述,并非所有引擎都支持明确的事务处理管理。MyISAM和InnoDB是两种最常使用 的引擎。前者不支持明确的事务处理管理,而后者支持。这 就是为什么本书中使用的样例表被创建来使用InnoDB而不是更经常使用的MyISAM的原因。如果你的应用中需要事务处理功能,则一定要使用正确的引擎类型。

26.2.1 使用ROLLBACK

SELECT * FROM ordertotals;
START TRANSACTION;
DELETE FROM ordertotals;
SELECT * FROM ordertotals;
ROLLBACK;
SELECT * FROM ordertotals;

哪些语句可以回退?
事务处理用来管理INSERT、UPDATE和DELETE语句。你不能回退SELECT语句。(这样做也没有什么意义。)你不能回退CREATE或DROP操作。事务处理块中可以使用这两条语句,但如果你执行回退,它们不会被撤销。

26.2.2 使用COMMIT

一般的MySQL语句都是直接针对数据库表执行和编写的。这就是 所谓的隐含提交(implicit commit),即提交(写或保存)操作是自动进行的。
但是,在事务处理块中,提交不会隐含地进行。为进行明确的提交, 使用COMMIT语句。

START TRANSACTION;
DELETE FROM orderitems WHERE order_num = 20010;
DELETE FROM orders WHERE order_num = 20010;
COMMIT;

最后的COMMIT语句仅在不出错时写出更改。如果第一条DELETE起作用,但第二条失败,则DELETE不会提交(实际上, 它是被自动撤销的)。

26.2.3 使用保留点

简单的ROLLBACK和COMMIT语句就可以写入或撤销整个事务处理。但 是,只是对简单的事务处理才能这样做,更复杂的事务处理可能需要部 分提交或回退。

SAVEPOINT delete1

每个保留点都可以起唯一的名字,回到指定的保留点

ROLLBACK TO delete1

第27章 全球化和本地化

27.1 字符集和校对顺序

数据库表被用来存储和检索数据。不同的语言和字符集需要以不同 的方式存储和检索。因此,MySQL需要适应不同的字符集(不同的字母和字符),适应不同的排序和检索数据的方法。
在讨论多种语言和字符集时,将会遇到以下重要术语:

  • 字符集为字母和符号的集合
  • 编码为某个字符集成员的内部表示
  • 校对为规定字符如何比较的指令

校对为什么重要
排序英文正文很容易,对吗?或许不。考虑词APE、apex和Apple。它们处于正确的排序顺序吗?这有赖于你是否想区分大小写。使用区分大小写的校对顺序,这些词有一种排序方式,使用不区分大小写的校对顺序有另外 一种排序方式。这不仅影响排序(如用ORDER BY排序数据),还影响搜索(例如,寻找apple的WHERE子句是否能找到 APPLE)。在使用诸如法文à或德文ö这样的字符时,情况更复 杂,在使用不基于拉丁文的字符集(日文、希伯来文、俄文等)时,情况更为复杂。

27.2 使用字符集和校对顺序

MySQL支持众多的字符集。为查看所支持的字符集完整列表,使用以下语句

SHOW CHARACTER SET;

这条语句显示所有可用的字符集以及每个字符集的描述和默认校对。

为了查看所支持校对的完整列表,使用以下语句:

SHOW COLLATION;

此语句显示所有可用的校对,以及它们适用的字符集。可以看到有的字符集具有不止一种校对。例如,latin1对不同的欧洲 语言有几种校对,而且许多校对出现两次,一次区分大小写(由_cs表示),一次不区分大小写(由_ci表示)。

实际上,字符集很少是服务器范围(甚至数据库范围)的 设置。不同的表,甚至不同的列都可能需要不同的字符集,而且两者都可以在创建表时指定

CREATE TABLE mytable(
    column1 INT,
    column2 VARVHAR(10),
) DEFAULT CHARACTER SET hebrew
  COLLATE hebrew_general_ci;

此语句创建一个包含两列的表,并且指定一个字符集和一个校对顺序。

也可以为列单独设置

CREATE TABLE mytable(
    column1 INT,
    column2 VARVHAR(10),
    column3 VARVHAR(10) CHARACTER SET latin1 COLLATE latin1_general_ci
) DEFAULT CHARACTER SET hebrew
  COLLATE hebrew_general_ci;

也可以在select时指定

SELECT * FROM  customers 
ORDER BY lastname, firstname COLLATE latin_general_cs;

临时区分大小写

上面的SELECT语句演示了在通常不区分大小写的表上进行区分大小写搜索的一种技术。当然,反过来也是可以的。

最后,值得注意的是,如果绝对需要,串可以在字符集之间进行转换。为此,使用Cast()或Convert()函数。

第28章 安全管理

第29章 数据库维护

第30章 改善性能

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,612评论 5 471
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,345评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,625评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,022评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,974评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,227评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,688评论 3 392
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,358评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,490评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,402评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,446评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,126评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,721评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,802评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,013评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,504评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,080评论 2 341