《MySQL必知必会》摘录与体会

来源:互联网 发布:网络插画班比较好的 编辑:程序博客网 时间:2024/05/18 14:26

1了解 SQL

1.1 数据库基础

1.1.1什么是数据库

数据库(database)保存有组织的数据的容器(通常是一个文件或一组文件)。

数据库软件应称为DBMS(数据库管理系统)。数据库是通过DBMS创建和操纵的容器。

补充:关系数据库与非关系数据库

关系数据库 - relational database,是一种通过建立索引来储存数据类型和他们之间的关联的技术。随着互联网的发展,有很多数据访问类型不再需要这种大型的关联逻辑,而是

需要储存和读取大量的数据。比如Facebook,人人之类的网站,他们的数据类型如果用关系数据库来表示,则又慢又占地方。

所以最近几年兴起的非关系数据库(NOSQL - No Only SQL),包括键值查询表数据库,图数据库等,就是针对这种不需要关联,不需要多个表JOIN,但是需要储存和读些大量数

据的情况而设计的。比如Graph Database,图数据库,储存的是一个Graph上的NodeEdge。这样比如查询你和我之间有多少个共同好友,或者像Linked-In那种查询两个用户之间

隔着几个人的查询,只需要做一个Graph Walk就可以。

非关系数据库的并没有关联的概念,它的前提条件就是数据不需要关联。当然,你可以通过Id和索引来读取多个表中的数据,然后手动将他们关联在一起。总的来说,非关系数

据库没有为这个情况做任何优化,也不适用于需要大量关联的数据。


1.1.2表

表(table)某种特定类型数据的结构化清单。这里关键的一点在于,存储在表中的数据是一种类型的数据或一个清单。

模式(schema)关于数据库和表的布局及特性的信息。


1.1.3列和数据类型

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

数据类型(datatype)所容许的数据的类型。每个表列都有相应的数据类型,它限制(或容许)该列中存储的数据。


1.1.4行

如果将表想象为网络,网络中垂直的列为表列,水平行为表行。行(row)表中的一个记录。

在很大程序上,记录和行是可以互相替代的,但从技术上说,行才是正确的术语。


1.1.5主键

主键(primary key)一列(或一组列),其值能够唯一区分表中每个行。

主键用来表示一个特定的行。没有主键,更新或删除表中特定行很困难,因为没有安全的方法保证只涉及相关的行。主键通常定义在表的一列上,但这并不是必需的,也可以一

起使用多个列作为主键。在使用多列作为主键时,上述条件必须应用到构成主键的所有列,所有列值的组合必须是唯一的(但单个列的值可以不唯一)。

表中的任何列都可以作为主键,只要它满足以下条件:

任意两行都不具有相同的主键值;

每个行都必须具有一个主键值(主键列不允许NULL值)。

主键的最好习惯

MySQL强制实施的规则外,应该坚持的几个普遍认可的最好习惯为:

不更新主键列中的值;

不重用主键列的值;

不在主键列中使用可能会更改的值。(例如,如果使用一个名字作为主键以标识某个供应商,当该供应商合并和更改其名字时,必须更改这个主键。)


1.2什么是SQL

SQL(发音为字母S-Q-Lsequel)是结构化查询语言(Structured Query Language)的缩写。SQL是一种专门用来与数据库通信的语言。


2 mysql 简介

2.1什么是MySQL

MySQL是一种DBMS,即它是一种数据库软件。


2.1.1客户机-服务器软件

DBMS可分为两类:一类为基于共享文件系统的DBMS,另一类为基于客户机-服务器的DBMS


2.2.1 mysql命令行实用程序

为了指定用户名登录名ben,应该使用

mysql -u ben

为了给出用户名、主机名、端口和口令,应该使用

mysql -u ben -p -h myserver -P 9999

mysql命令行实用程序是使用最多的实用程序之一,它对于快速测试和执行脚本非常有价值。

使用 mysql

3.1 连接

MySQL与所有客户机——服务器DBMS一样,要求在能执行命令之前登录到DBMS。为了连接到MySQL,需要以下信息:

主机名(计算机名)——如果连接到本地MySQL服务器,为localhost

补充:在计算机网络中,localhost(意为“本地主机”,指“这台计算机”)是给回路网络接口(loopback)的一个标准主机名,相对应的IP地址为127.0.0.1IPv4

[::1]IPv6)。

端口(如果使用默认端口3306之处的端口);

一个合法的用户名;

用户口令(如果需要)。


3.2选择数据库

在你最初连接到MySQL时,没有任何数据库打开供你使用。在你能执行任意数据库操作前,需要选择一个数据库。为此,可使用USE关键字。如:

USE crashcourse;

USE语句并不返回任何结果。


3.3了解数据库和表

如果你不知道可以使用的数据库名时怎么办?

数据库、表、列、用户、权限等的信息被存储在数据库和表中(MySQL使用mysql来存储这些信息)。不过,内部的表一般不直接访问。可用MySQLSHOW命令来显示这些

信息(MySQL从内部表中提取这些信息)。

SHOW DATABASES;

返回可用数据库的一个列表。包含在这个列表中的可能是MySQL内部使用的数据库(如mysqlinformation_schema)。

获得一个数据库的表的列表:

SHOW TABLES;

返回当前选择的数据库内可用表的列表。

SHOW也可以用来显示表列:

SHOW COLUMNS FROM customers;

它对每个字段返回一行,行中包含字段名。数据类型、是否允许NULL、键信息、默认值以及其他信息。

MySQL支持用DESCRIBE作为SHOW COLUMNS FROM的一种快捷方式。如:

DESCRIBE customers

SHOW STATUS;用于显示广泛的服务器状态信息。

SHOW CREATE DATABASE;SHOW CREATE TABLE;,分别用来显示创建特定数据库或表的MySQL语句。

SHOW GRANTS;用来显示授予用户(所有用户或特定用户)的安全权限。

SHOW ERRORS;SHOW WARNINGS;,用来显示服务器错误或警告消息。

显示允许的SHOW语句

HELP SHOW;

什么是自动增量?某些表列需要唯一值。例如,订单编号、雇员ID或(如上面例子中所示的)顾客ID。在每个行添加到表中时,MySQL可以自动地为每个行分配下一个可用编号,不用在添加一行时手动分配唯一值(这样做必须记住最后一次使用的值)。这个功能就是所谓的自动增量。


检索数据

4.1select语句

它的用途是从一个或多个表中检索信息。

4.2检索单个列

如:利用SELECT语句从products表中检索一个名为prod_name的列。

SELECT prod_name

FROM products;

返回表中所有行。数据没有过滤(过滤将得出结果集的一个子集),也没有排序。

注意:SQL语句不区分大小写,因此SELECTselect是相同的。许多SQL开发人员喜欢以所有SQL关键字使用大写,而对所有列和表名使用小写,这样做使代码更易于阅读和调

试。

4.3检索多个列

下面的SELECT语句从products表中选择3列:

SELECT prod_id,prod_name,prod_price

FROM products;

数据表示:从上述输出可以看到,SQL语句一般返回原始的、无格式的数据。

4.4检索所有列

SELECT *

FROM products;

4.5检索不同的行

使用DISTINCT关键字,返回不同的值。

SELECT DISTINCT vend_id

FROM product;

不能部分使用DISTINCT,如果给出SELECT DISTINCT vend_id;除非指定的两个列都不同,否则所有行都将被检索出来。

4.6限制结果

SELECT prod_name

FROM products

LIMIT 5;

此语句使用SELECT语句检索单个列。LIMIT 5指示MySQL返回不多于5行。

SELECT prod_name

FROM products

LIMIT 5,5;

LIMIT 5,5指示MySQL返回从行5开始的5行。

所以,带一个值的LIMIT总是从第一行开始,给出的数为返回的行数。带两个值的LIMIT可以指定从行号为第一个值的位置开始。

检索出来的第一行为行0而不是行1。因此,LIMIT 1,1将检索出第二行而不是第一行。

4.7使用完全限定的表名

SELECT products.prod_name

FROM crashcourse.products;


排序检索数据

5.1排序数据

SELECT prod_name

FROM products

ORDER BY prod_name;

这条语句除了指示MySQLprod_name列以字母顺序排序数据的ORDER BY子句外,与前面的语句相同。


5.2按多个列排序

SELECT prod_id,prod_price,prod_name

FROM products

ORDER BY prod_price,prod_name;

首先按价格,然后再按名称排序。


5.3指定排序方向

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关键字。

系统默认升序:ASC

SELECT prod_price

FROM products

ORDER BY prod_price DESC

LIMIT 1;

找出一个列中最高或最低的值。

ORDER BY子句的位置

在给出ORDER BY子句时,应该保证它位于FROM子句之后。如果使用LIMIT,它必须位于ORDER BY之后。使用子句的次序不对将产生错误消息。


过滤数据

6.1使用WHERE子句

SELECT prod_name,prod_price

FROM products

WHERE prod_price = 2.50;

products表中检索两个列,但不返回所有行,只返回prod_price值为2.50的行。

WHERE子句的位置,在同时使用ORDER BYWHERE子句时,应该让ORDER BY位于WHERE之后,否则将会产生错误。


6.2 WHERE子句操作符

=等于

<>!=不等于

<小于

<=小于等于

>大于

>=大于等于

BETWEEN在指定的两个值之间

SELECT prod_name,prod_price

FROM products

WHERE prod_price BETWEEN 5 AND 10;

检索价格在5美无和10美元之间的所有产品。

空值检查

SELECT prod_name

FROM products

WHERE prod_price IS NULL;

返回没有价格的所有产品。



数据过滤

7.1组合WHERE子句

7.1.1 AND操作符

SELECT prod_id,prod_price,prod_name

FROM products

WHERE vend_id = 1003 AND prod_price <= 10;

检索由供应商1003制造且价格小于等于10美无的所有产品和名称和价格。


7.1.2 OR操作符

SELECT prod_name,prod_price

FROM products

WHERE vend_id = 1002 OR vend_id = 1003;

SQL语句检索由任一个指定供应商制造的所有产品的产品名和价格。OR操作符告诉DBMS匹配任一条件而不是同时匹配两个条件。如果这里使用的是AND操作符,则没有数

据返回(此时创建的WHERE子句不会检索到匹配的产品)。


7.1.3 计算次序

SELECT prod_name,prod_price

FROM products

WHERE(vend_id = 1002 OR vend_id = 1003) AND prod_price >= 10;

在where子句中使用圆括号 任何时候使用具有andor操作符的where子句,都应该使用圆括号明确地分组操作符。不要过分依赖默认计算次序,即使它确实是你想要的东西也是

如此。使用圆括号没有什么坏处,它能消除歧义。


7.2 IN操作符

SELECT prod_name,prod_price

FROM products

WHERE vend_id IN(1002,1003)

ORDER BY prod_name;

检索供应商10021003制造的所有产品。

IN操作符完成与OR相同的功能。

为什么要使用IN操作符?

-在使用长的合法选项清单时,IN操作符的语法更清楚且更直观。

-在使用IN时,计算的次序更容易管理(因为使用的操作符更少)。

IN操作符一般比OR操作符清单执行更快。

IN的最大优点是可以包含其他SELECT语句,使得能够更动态地建立WHERE子句。


7.3 NOT操作符

SELECT prod_name,prod_price

FROM products

WHERE vend_id NOT IN(1002,1003)

ORDER BY prod_name;

列出除10021003之外的所有供应商制造的产品。


用通配符进行过滤

8.1 LIKE操作符

8.1.1 百分号(%)通配符

SELECT prod_id,prod_name

FROM products

WHERE prod_name LIKE 'jet%';

检索任意以jet起头的词。

SELECT prod_id,prod_name

FROM products

WHERE prod_name LIKE '%anvil%';

搜索模式'%anvil%'表示匹配任何位置包含文本anvil的值,而不论它之前或之后出现什么字符。

SELECT prod_id

FROM products

WHERE prod_name LIKE 's%e';

找出以s起头以e结尾的所有产品。

%通配符不能匹配NULL


8.1.2下划线(-)通配符

下划线的用途与%一样,但下划线只匹配单个字符而不是多个字符。

SELECT prod_id,prod_name

FROM products

WHERE prod_name LIKE '_ ton anvil'


8.2使用通配符的技巧

通配符搜索的处理一般要比前面讨论的其他搜索所花时间更长。这里给出一些使用通配符要记住的技巧:

-不要过度使用通配符。如果其他操作符能达到相同的目的,应该使用其他操作符。

-在确实需要使用通配符时,除非绝对有必要,否则不要把它们用在搜索模式的开始处。把通配符置于搜索模式的开始处,搜索起来是最慢的。

-仔细注意通配符的位置。如果放错地方,可能不会返回想要的数据。


用正则表达式进行搜索

正则表达式是用来匹配文本的特殊的串(字符集合)。正则表达式用正则表达式语言来建立,正则表达式语言是用来完成刚讨论的所有工作以及更多工作的一种特殊语言。与任

意语言一样,正则表达式具有你必须学习的特殊的语法和指令。


10 创建计算字段

10.1计算字段

如果存储在表中的数据都不是应用程序所需要的。我们需要直接从数据库中检索出转换、计算或格式化过的数据;而不是检索出数据,然后再在客户机应用程序或报告程序中重

新格式化。

这就是计算字段发挥作用的所在了。与前面各章介绍过的列不同,计算字段并不实际存在于数据库表中。计算字段是运行时在SELECT语句内创建的。

字段(field)基本上与列(column)的意思相同,经常互换使用,不过数据列一般称为列,而术语字段通常用在计算字段的连接上。


10.2拼接字段

SELECT Concat(vend_name,'(',vend_country,')')

FROM vendors

ORDER BY vend_name;

+----------------------------------------+

| Concat(vend_name,'(',vend_country,')') |

+----------------------------------------+

| ACME(USA)                              |

| Anvils R Us(USA)                       |

| Furball Inc.(USA)                      |

| Jet Set(England)                       |

| Jouets Et Ours(France)                 |

| LT Supplies(USA)                       |

+----------------------------------------+

上面的SELECT语句连接以下4个元素:

-存储在vend_name列中的名字;

-包含一个空格和一个左圆括号的串;

-存储在vend_country列中的国家

通过RTrim()函数可以删除数据右侧多余的空格来整理数据。

使用别名

SELECT Concat(RTrim(vend_name),'(',RTrim(vend_country),')') AS vend_title

FROM vendors

ORDER BY vend_name;

+------------------------+

| vend_title             |

+------------------------+

| ACME(USA)              |

| Anvils R Us(USA)       |

| Furball Inc.(USA)      |

| Jet Set(England)       |

| Jouets Et Ours(France) |

| LT Supplies(USA)       |

+------------------------+

它指示SQL创建一个包含指定计算的名为vend_title的计算字段。别名有时也称为导出列(derived column)。


10.3 执行算术计算

SELECT prod_id,quantity,item_price,quantity*item_price AS expanded_price

FROM orderitems

WHERE order_num = 20005;

输出中显示的expanded_price列为一个计算字段。MySQL算术操作符:+ - * / 


11 使用数据处理函数

11.1函数

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


11.2 使用函数

11.2.1文本处理函数

SELECT vend_name,Upper(vend_name) AS vend_name_upcase

FROM vendors

ORDER BY vend_name;

Upper()将文本转换为大写。

常用的文本处理函数

Left() 返回串左边的字符

Length() 返回串的长度

Locate() 找出串的一个子串

Lower() 将串转换为小写

LTrim() 去掉串左边的空格

Right() 返回串右边的字符

RTrim() 去掉串右边的空格

Soundex() 返回串的SOUNDEX

SubString() 返回子串的字符

Upper() 将串转换为大写

SELECT cust_name,cust_contact

FROM customers

WHERE Soundex(cust_contact) = Soundex('Y.Lie');

它匹配所有发音类似于Y.Lie的联系名。


11.2.2 日期和时间处理函数

常用日期和时间处理函数

AddDate() 增加一个日期(天、周等)

AddTime() 增加一个时间(时、分等)

CurDate() 返回当前日期

CurTime() 返回当前时间

Date() 返回日期时间的日期部分

DateDiff() 计算两个日期之差

Date_Add() 高度灵活的日期运算函数

Date_Format() 返回一个格式化的日期或时间串

Day() 返回一个日期的天数部分

DayOfWeek() 对于一个日期,返回对应的星期几

Hour() 返回一个时间的小时部分

Minute() 返回一个时间的分钟部分

Month() 返回一个日期的月份部分

Now() 返回当前日期和时间

Second() 返回一个时间的秒部分

Time() 返回一个日期时间的时间部分

Year() 返回一个日期的年份部分

SELECT cust_id,order_num

FROM orders

WHERE Date(order_date) = '2005-09-01';

检索出一个订单记录,该订单记录的order_date2005-09-01

SELECT cust_id,order_num

FROM orders

WHERE Date(order_date) BETWEEN '2005-09-01' AND '2005-09-30';

BETWEEN操作符用来把2005-09-012005-09-30定义为一个要匹配的日期范围。

SELECT cust_id,order_num

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汇总数据

12.1 聚焦函数

我们经常需要汇总数据而不用把它们实际检索出来,MySQL提供了专门的函数,查询可用于检索数据,以便分析和报表生成。这种类型的检索例子有以下几种:

-确定表中行数(或者满足某个条件或包含某个特定值的行数)。

-获得表中行组的和。

-找出表列(或所有行或某些特定的行)的最大值、最小值和平均值。

上述例子都需要对表中数据(而不是实际数据本身)汇总。因此,返回实际表数据是对时间和处理资源的一种浪费(更不用说带宽了)。

聚集函数(aggregate function)运行在行组上,计算和返回单个值的函数。

SQL聚集函数:

AVG() 返回某列的平均值

COUNT() 返回某列的行数

MAX() 返回某列的最大值

MIN() 返回某列的最小值

SUM() 返回某列值之和

SELECT AVG(prod_price) AS avg_price

FROM products;

返回products表中所有产品的平均价格。

SELECT AVG(prod_price) AS avg_price

FROM products

WHERE vend_id = 1003;

返回该供应商的产品的平均值。

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

SELECT COUNT(*) AS num_cust

FROM customers;

返回customers表中客户的总数

SELECT MAX(prod_price) AS max_price

FROM products;

返回products表中最贵的物品的价格。

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

SELECT MIN(prod_price) AS min_price

FROM products;

返回products表中最便宜的物品的价格。

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

SELECT SUM(quantity) AS items_ordered

FROM orderitems

WHERE order_num = 20005;

返回订单中所有物品数量之和,WHERE子句保证只统计某个物品订单中的物品。

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

12.2 聚集不同值

SELECT AVG(DISTINCT prod_price) AS avg_price

FROM products

WHERE vend_id = 1003;

排除相同价格后,平均价格提升了。

12.3 组合聚集函数

SELECT COUNT(*) AS num_items,

MIN(prod_price) AS price_min,

MAX(prod_price) AS price_max,

AVG(prod_price) AS price_avg

FROM products;

返回物品的数目,产品价格的最高、最低以及平均值。


13 分组数据

13.2创建分组

SELECT vend_id,COUNT(*) AS num_prods

FROM products

GROUP BY vend_id;

GROUP BY子句指示MySQL分组数据,然后对每个组而不是整个结果集进行聚集。


13.3过滤分组

除了能用GROUP BY分组数据外,MySQL还允许过滤分组,规定包括哪些分组,排除哪些分组一。WHERE过滤指定的是行而不是分组。事实上,WHERE没有分组的概念。HAVING非常类似于WHERE。事实上,目前为止所学过的所有类型的WHERE子句都可以用HAVING来替代。唯一的差别是WHERE过滤行,而HAVING过滤分组。

HAVING支持所有WHERE操作符:我们所学习了WHERE子句的条件(包括通配符条件和带多个操作符的子句)。所学过的有关WHERE的所有技术和选项都适用于HAVING。它们的句法是相同的,只是关键字有差别。

SELECT cust_id,COUNT(*) AS orders

FROM orders

GROUP BY cust_id

HAVING COUNT(*) >= 2;

过滤COUNT(*) >= 2 (两个以上的订单)的那些分组。

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

虽然GROUP BYORDER BY经常完成相同的工作,但它们是非常不同的。


14 使用子查询

查询(query)任何SQL语句都是查询。但此术语一般指SELECT语句。

WHERE子句中使用子查询,应该保证SELECT语句具有与WHERE子句中相同数目的列。通常,子查询将返回单个列并且与单个列匹配,但如果需要也可以使用多个列。

虽然子查询一般与IN操作符结合使用,但也可以用于测试等于(=)、不等于(<>)等。


15 联结表

15.1联结

15.1.1关系表

关系表的设计就是要保证把信息分解成多个表,一类数据一个表。各表通过某些常用的值(即关系设计中的关系(relational))互相关联。

外键(foreign key)为某个表中的一列,它包含另一个表的主键值,定义了两个表之间的关系。关系数据可以有效地存储和方便地处理。因此,关系数据库的可伸缩性远比非关

系数据库要好。

能够适应不断增加的工作量而不失败。设计良好的数据库或应用程序称之为可伸缩性好(scale well)。


15.1.2为什么要使用联结

联结是一种机制,用来在一条SELECT语句中关联表。使用特殊的语法,可以联结多个表返回一组输出,联结在运行时关联表中正确的行。


15.2创建联结

SELECT vend_name,prod_name,prod_price

FROM vendors,products

WHERE vendors.vend_id = products.vend_id

ORDER BY vend_name,prod_name;

指定两个列(prod_nameprod_price)在一个表中,而另一个列(vend_name)在另一个表中。


15.2.2 内部联结

目前为止所用的联结称为等值联结(equijoin),它基于两个表之间的相等测试。这种联结也称为内部联结。

完全限定列名:在引用的列可能出现二义性时,必须使用完全限定列名(用一个点分隔的表名和列名)。如果引用一个没有用表名限制的具有二义性的列名,MySQL将返回错

误。


15.2.3 联结多个表

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 = 20005;

显示编号为20005的订单中的物品。


16 创建高级联结

16.1 使用表别名

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 = 'TNT2';


16.2使用不同类型的联结

16.2.1自联结

自联结通常作为外部语句用来替代从相同表中检索数据时使用的子查询语句。虽然最终的结果是相同的,但有时候处理联结远比处理子查询快得多。


16.2.2自然联结

自然联结排除多次出现,使每个列只返回一次。


16.2.3外部联结

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


17 组合查询

17.2创建组合查询

可用UNION操作符来组合数条SQL查询。利用UNION,可给出多条SELECT语句,将它们的结果组合成单个结果集。


17.2.3包含或取消重复的行

UNION从查询结果集中自动去除了重复的行(换句话说,它的行为与单条SELECT语句中使用多个WHERE子句条件一样)。

这是UNION的默认行为,但是如果需要,可以改变它。事实上,如果想返回所有匹配行,可使用UNION ALL而不是UNION


17.2.4对组合查询结果排序

SELECT语句的输出用ORDER BY子句排序。在用UNION组合查询时,只能使用一条ORDER BY子句,它必须出现在最后一条SELECT语句之后。对于结果集,不存在用一种方

式排序一部分,而又用另一种方式排序另一部分的情况,因此不允许使用多条ORDER BY子句。


18 全文本检索

18.1理解全文本搜索

在使用全文本搜索时,MySQL不需要分别查看每个行,不需要分别分析和处理每个词。MySQL创建指定列中各词的一个索引,搜索可以针对这些词进行。这样,MySQL可以

快速有效地决定哪些词匹配(哪些行包含它们),哪些词不匹配,它们匹配的频率,等等。


18.2使用全文本搜索

18.2.4布尔文本搜索

布尔方式不同于迄今为止使用的全文本搜索语法的地方在于,即使没有定义FULLTEXT索引,也可以使用它。但这是一种非常缓慢的操作(其性能将随着数据量的增加而降

低)。

在布尔方式中,不按等级值降序排序返回的行。


18.2.5全文本搜索的使用说明

邻近搜索是许多全文本搜索支持的一个特性,它能搜索相邻的词(在相同的句子中、相同的段落中或者在特定数目的词的部分中,等等)。MySQL全文本搜索现在还不支持邻

近操作符,不过未来的版本有支持这种操作符的计划。


19 数据插入

19.4插入检索出的数据

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

它是由一条INSERT语句和一条SELECT语句组成的。

INSERT INTO Customers

VALUES(NULL,

         'Pep E. LaPew',

         '100 Main Street',

         'Los Angeles',

         'CA',

         '90046',

         'USA',

         NULL

         NULL);

插入一个新客户到customers表。

INSERT语句一般不会产生输出。

编写更安全的INSERT语句

INSERT INTO Customers(cust_name,

         cust_address,

         cust_city,

         cust_state,

         cust_zip,

         cust_country,

         cust_contact,

         cust_email)

VALUES(NULL,

         'Pep E. LaPew',

         '100 Main Street',

         'Los Angeles',

         'CA',

         '90046',

         'USA',

         NULL

         NULL);


20  更新和删除数据

20.3更新和删除的指导原则

MySQL没有撤销(undo)按钮。应该非常小心地使用UPDATEDELETE,否则你会发现自己更新或删除了错误的数据。

UPDATE customers

SET cust_email = 'elmer@fudd.com'

WHERE cust_id = 10005;

更新客户10005现在的电子邮件地址。

UPDATE语句以WHERE子句结束,它告诉MySQL更新哪一行。没有WHERE子句,MySQL将会用这个电子邮件地址更新customers表中所有行,这不是我们所希望的。

UPDATE customers

SET cust_name = 'The Fudds',

cust_email = 'elmer@fudd.com'

WHERE cust_id = 10005;

更新客户10005cust_namecust_email列。

UPDATE customers

SET cust_email = NULL

WHERE cust_id = 10005;

其中NULL用来去除cust_email列中的值。

DELETE FROM customers

WHERE cust_id = 10006;

customers表中删除一行。

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

如果想从表中删除所有行,不要使用DELETE。可使用TRUNCATE TABLE语句,它完成相同的工作,但速度更快(TRUNCATE实际是删除原来的表并重新创建一个表,而不

是逐行删除表中的数据)。


21 创建和操纵表

21.1创建表

21.1.1表创建基础

CREATE TABLE customers

(

  cust_id      int       NOT NULL AUTO_INCREMENT,

  cust_name    char(50)  NOT NULL ,

  cust_address char(50)  NULL ,

  cust_city    char(50)  NULL ,

  cust_state   char(5)   NULL ,

  cust_zip     char(10)  NULL ,

  cust_country char(50)  NULL ,

  cust_contact char(50)  NULL ,

  cust_email   char(255) NULL ,

  PRIMARY KEY (cust_id)

) ENGINE=InnoDB;

如果你仅想在一个表不存在时创建它,应该在表名后给出IF NOT EXISTS。这样做不检查已有表的模式是否与你打算创建的表模式相匹配。它只是查看表名是否存在,并且仅在

表名不存在时创建它。

补充:

DROP TABLE IF EXISTS `custnew`;

CREATE TABLE `custnew` (

  `cust_id` int(11) NOT NULL AUTO_INCREMENT,

  `cust_name` char(50) NOT NULL,

  `cust_address` char(50) DEFAULT NULL,

  `cust_city` char(50) DEFAULT NULL,

  `cust_state` char(5) DEFAULT NULL,

  `cust_zip` char(10) DEFAULT NULL,

  `cust_country` char(50) DEFAULT NULL,

  `cust_contact` char(50) DEFAULT NULL,

  `cust_email` char(255) DEFAULT NULL,

  PRIMARY KEY (`cust_id`)

) ENGINE=InnoDB DEFAULT CHARSET=latin1;

在创建新表时,指定的表名必须不存在,否则将出错。如果要防止意外覆盖已有的表,SQL要求首先手工删除该表,然后再重建它,而不是简单地用创建表语句覆盖它。


21.1.2使用NULL值

不要把NULL值与空串相混淆。NULL值是没有值,它不是空串。如果指定‘’(两个单引号,期间没有字符),这在NOT NULL列中是允许的。空串是一个有效的值,它不是无值。NULL值用关键字NULL而不是空串指定。


21.1.3主键再介绍

主键值必须唯一。即,表中的

每个行必须具有唯一的主键值。如果主键使用单个列,则它的值必须唯一。如果使用多个列,则这些列的组合值必须唯一。

主键中只能使用不允许NULL值的列。允许NULL值的列不能作为唯一标识。


21.1.4使用AUTO_INCREMENT

MySQL生成(通过自动增量)主键的一个缺点是你不知道这些值都是谁。


21.2更新表

使用ALTER TABLE 要极为小心,应该在进行改动前做一个完整的备份(模式和数据的备份)。数据库表的更改不能撤销,如果增加了不需要的列,可能不能删除它们。类似

地,如果删除了不应该删除的列,可能会丢失该列中的所有数据。

ALTER TABLE vendors

ADD vend_phone CHAR(20);

vendors表增加一个名为vend_phone的列,必须明确其数据类型。

ALTER TABLE vendors

DROP COLUMN vend_phone;

删除刚刚添加的列。

ALTER TABLE定义外键。

ALTER TABLE orderitems 

ADD CONSTRAINT fk_orderitems_orders 

FOREIGN KEY (order_num) REFERENCES orders (order_num);

ALTER TABLE orderitems 

ADD CONSTRAINT fk_orderitems_products 

FOREIGN KEY (prod_id) REFERENCES products (prod_id);

ALTER TABLE orders 

ADD CONSTRAINT fk_orders_customers 

FOREIGN KEY (cust_id) REFERENCES customers (cust_id);

ALTER TABLE products 

ADD CONSTRAINT fk_products_vendors 

FOREIGN KEY (vend_id) REFERENCES vendors (vend_id);


21.3删除表

DROP TABLE customers2;


21.4 重命名表

RENAME TABLE customers2 TO customers;


22 使用视图

22.1视图

视图是虚拟的表。与包含数据的表不一样,视图只包含使用时动态检索数据的查询。

视图不包含表中应该有的任何列或数据,它包含的是一个SQL查询(与上面用以正确联结表的相同的查询)。

视图仅仅是用来查看存储在别处的数据的一种设施。视图本身不包含数据,因此它们返回的数据是从其他表中检索出来的。在添加或更改这些表中的数据时,视图将返回改变过

的数据。

因为视图不包含数据,所以每次使用视图时,都必须处理查询执行时所需的任一个检索。如果你用多个联结和过滤创建了复杂的视图或者嵌套了视图,可能会发现性能下降得很

厉害。因此,在部署使用了大量视图的应用前,应该进行测试。


22.2 使用视图

-视图用CREATE VIEW语句来创建。

-使用SHOW CREATE VIEW viewname;来查看创建视图的语句。

-用DROP删除视图,其语法为DROP VIEW viewname;

-更新视图时,可以选用DROP再用CREATE,也可以直接用CREATE OR REPLACE VIEW。如果要更新的视图不存在,则第2条更新语句会创建一个视图;如果要更新的视图

存在,则第2条更新语句会替换原有视图。


22.2.1利用视图简化复杂的联结

创建不受特定数据限制的视图是一种好办法。扩展视图的范围不仅使得它能被重用,而且甚至更有用。这样做不需要创建和维护多个类似视图。

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;

将列出订购了任意产品的客户。


22.2.2用视图重新格式化检索出的数据

视图的另一常见用途是重新格式化检索出的数据。


22.2.5更新视图

通常,视图是可更新的(即,可以对它们使用INSERTUPDATEDELETE)。更新一个视图将更新其基表(视图本身没有数据)。如果你对视图增加或删除行,实际上是对

其基表增加或删除行。


23 使用存储过程

补充:本质上没区别。只是函数有如:只能返回一个变量的限制。而存储过程可以返回多个。而函数是可以嵌入在sql中使用的,可以在select中调用,而存储过程不行。执行的本

质都一样。


23.1存储过程

存储过程简单来说,就是为以后的使用而保存的一条或多条MySQL语句的集合。可将其视为批文件,虽然它们的作用不仅限于批处理。


23.3使用存储过程

23.3.1执行存储过程

CALL productpricing(@pricelow,

                  @pricehigh,

                  @priceaverage);

其中,执行名为productpricing的存储过程,它计算并返回产品的最低、最高和平均价格。

补充:存储过程实际上是一种函数,所以存储过程名后需要有()符号(即使不传递参数也需要)。


23.3.2 创建存储过程

CREATE PROCEDURE productpricing()

BEGIN

SELECT Avg(prod_price) AS priceaverage

FROM products;

END;

此存储过程名为productpricing,用CREATE PROCEDURE productpricing()语句定义。


23.3.3 删除存储过程

DROP PROCEDURE productpricing;

如果过程不存在也不产生错误,可使用DROP PROCEDURE IF EXISTS


23.3.4使用参数

所有MySQL变量都必须以@开始。一般,存储过程并不显示结果,而是把结果返回给你指定的变量。

补充:这里可以看出存储过程和函数的区别,就在返回值的个数上。

变量(variable)内存中一个特定的位置,用来临时存储数据。

CREATE PROCEDURE productpricing(

OUT pl DECIMAL(8,2),

OUT ph DECIMAL(8,2),

OUT pa DECIMAL(8,2)

)

BEGIN 

    SELECT Min(prod_price) 

    INTO pl 

    FROM products; 

    SELECT Max(prod_price) 

    INTO ph 

    FROM products; 

    SELECT Avg(prod_price) 

    INTO pa 

    FROM products; 

END;

此存储过程接受3个参数;pl存储产品最低价格,ph存储产品最高价格,pa存储产品平均价格。每个参数必须具有指定的类型,这里使用十进制值。关键字OUT指出相应的参数

用来从存储过程传出一个值(返回给调用者)。MySQL支持IN(传递给存储过程)、OUT(从存储过程传出)和INOUT(对存储过程传入和传出)类型的参数。存储过程的代

码位于BEGINEND语句内,如前所见,它们是一系列SELECT语句,用来检索值,然后保存到相应的变量(通过指定INTO关键字)。

CREATE PROCEDURE ordertotal(

IN onumber INT,

OUT ototal DECIMAL(8,2)

)

BEGIN

SELECT Sum(item_price*quantity)

FROM orderitems

WHERE order_num = onumber

INTO ototal;

END;

onumber定义为IN,因为订单被传入存储过程。ototal定义为OUT,因为要从存储过程返回合计。

CALL ordertotal(20005,@total);

调用这个新存储过程。

-- Name:ordertotal

-- Parameters:onumber = order number

--          taxable = 0 if not taxable,1 if taxable

--          ototal = order total variable

CREATE PROCEDURE ordertotal(

IN onumber INT,

IN taxable BOOLEAN,

OUT ototal DECIMAL(8,2)

)COMMENT 'Obtain order toal,optionally adding tax'

BEGIN

-- Declare variable for total

DECLARE total DECIMAL(8,2);

-- Declare tax percentage

DECLARE taxrate INT DEFAULT 6;

-- Get the order total

SELECT Sum(item_price*quantity)

FROM orderitems

WHERE order_num = onumber

INTO total;

-- Is this taxable?

IF taxable THEN

   -- Yes,so add taxrate to the total

   SELECT total+(total/100*taxrate) INTO total;

END IF;

-- And finally,save to out variable

SELECT total INTO ototal;

END;

此存储过程有很大的变动。首先,增加了注释(前面放置--)。在存储过程复杂性增加时,这样做特别重要。添加了另外一个参数taxable,它是一个布尔值(如果要增加税则为

真,否则为假)。在存储过程体中,用DECLARE语句定义了两个局部变量。DECLARE要求指定变量名和数据类型,它也支持可选的默认值(这个例子中的taxrate的默认被设置

6%)。SELECT语句已经改变,因此其结果存储到total(局部变量)而不是ototalIF语句检查taxable是否为真,如果为真,则用另一SELECT语句增加营业税到局部变

total。最后,用另一SELECT语句将total(它增加或许不增加营业税)保存到ototal

COMMENT关键字:本例子中的存储过程在CREATE PROCEDURE 语句中包含了一个COMMENT值。它不是必需的,但如果给出,将在SHOW PROCEDURE STATUS的结果中显示。

补充:注意,在--后留个空格。

23.3.6 检查存储过程

为显示用来创建一个存储过程的CREATE语句,使用SHOW CREATE PROCEDURE语句:

SHOW CREATE PROCEDURE ordertotal;

为了获得包括何时、由谁创建等详细信息的存储过程列表,使用SHOW PROCEDURE STATUS


C语言调用存储过程并且获得返回值:http://blog.csdn.net/ytz_linuxer/article/details/4435056

24 使用游标

24.1游标

游标(cursor)是一个存储在MySQL服务器上的数据库查询,它不是一条SELECT语句,而是被该语句检索出来的结果集。在存储了游标之后,应用程序可以根据需要滚动或浏

览其中的数据。

游标主要用于交互式应用,其中用户需要滚动屏幕上的数据,并对数据进行浏览或做出更改。

不像多数DBMSMySQL游标只能用于存储过程(和函数)。

如果你不明确关闭游标,MySQL将会在到达END语句时自动关闭它。


25 使用触发器

25.1触发器

触发器是MySQL响应以下任意语句而自动执行的一条MySQL语句(或位于BEGINEND语句之间的一组语句):

DELETE;

INSERT;

UPDATE

其他MySQL语句不支持触发器。


25.2 创建触发器

在创建触发器时,需要给出4条信息:

-唯一的触发器名;

-触发器关联的表;

-触发器应该响应的活动(DELETEINSERTUPDATE);

-触发器何时执行(处理之前或之后)。

CREATE TRIGGER newproduct AFTER INSERT ON products

FOR EACH ROW SELECT 'Product added';

CREATE TRIGGER用来创建名为newproduct的新触发器。触发器可在一个操作发生之前或之后执行,这里给出了AFTER INSERT,所以此触发器将在INSERT语句成功执行后执

行。这个触发器还指定FOR EACH ROW,因此代码对每个插入行执行。在这个例子中,文本Product added将对每个插入的行显示一次。

只有表才支持触发器,视图不支持(临时表也不支持)。

触发器按每个表每个事件每次地定义,每个表每个事件每次只允许一个触发器。因此,每个表最多支持6个触发器(每条INSERTUPDATEDELETE的之前和之后)。单一触

发器不能与多个事件或多个表关联,所以,如果你需要一个对INSERTUPDATE操作执行的触发器,则应该定义两个触发器。


25.3删除触发器

DROP TRIGGER newproduct;


25.4 使用触发器

25.4.1 INSERT触发器

INSERT触发器在INSERT语句执行之前或之后执行。

-在INSERT触发器代码内,可引用一个名为NEW的虚拟表,访问被插入的行;

-在BEFORE INSERT触发器中,NEW中的值也可以被更新(允许更改被插入的值);

-对于AUTO_INCREAMENT列,NEW在INSERT执行之前包含0,在INSERT执行之后包含新的自动生成值。

CREATE TRIGGER neworder AFTER INSERT ON orders

FOR EACH ROW SELECT NEW.order_num;

此代码创建一个名为neworder的触发器,它按照AFTER INSERT ON orders执行。在插入一个新订单到orders表时,MySQL生成一个新订单号并保存到order_num中。触发器

NEWorder_num取得这个值并返回它。

通常,将BEFORE用于数据验证和净化(目的是保证插入表中的数据确实是需要的数据)。本提示也适用于UPDATE触发器。


25.4.2 DELETE触发器

DELETE触发器在DELETE语句执行之前或之后执行。需要知道以下两点:

-在DELETE触发器代码内,你可以引用一个名为OLD的虚拟表,访问被删除的行;

-OLD中的值全都是只读的,不能更新。

CREATE TRIGGER deleteorder BEFORE DELETE ON orders

FOR EACH ROW

BEGIN

INSERT INTO archive_orders(order_num,order_date,cust_id)

VALUES(OLD.order_num,OLD.order_date,OLD.cust_id);

END;

在任意订单被删除前将执行此触发器。它使用一条INSERT语句将OLD中的值(要被删除的订单)保存到一个名为archive_orders的存档表中(为实际使用这个例子,你需要用

orders相同的列创建一个名为archive_orders的表)。

使用BEFORE DELETE触发器的优点(相对于AFTER DELETE触发器来说)为,如果由于某种原因,订单不能存档,DELETE本身将被放弃。

多语句触发器

正如所见,触发器deleteorder使用BEGINEND语句标记触发器体。这在此例子中并不是必需的,不过也没有害处。使用BEGIN END块的好处是触发器能容纳多条SQL语句

(在BEGIN END块中一条挨着一条)。


25.4.3 UPDATE触发器

UPDATE触发器在UPDATE语句执行之前或之后执行。需要知道以下几点;

-在UPDATE触发器代码中,你可以引用一个名为OLD的虚拟表访问以前(UPDATE语句前)的值,引用一个名为NEW的虚拟表访问新更新的值;

-在BEFORE UPDATE触发器中,NEW中的值可能也被更新(允许更改将要用于UPDATE语句中的值);

-OLD中的值全都是只读的,不能更新。

CREATE TRIGGER updatevendor BEFORE UPDATE ON vendors

FOR EACH ROW SET NEW.vend_state = Upper(NEW.vend_state);

每次更新一个行时,NEW.vend_state中的值(将用来更新表行的值)都用Upper(NEW.vend_state)替换。

MySQL触发器中不支持CALL语句。这表示不能从触发器内调用存储过程。所需的存储过程代码需要复制到触发器内。


26 管理事务处理

26.1事务处理

事务(transaction)指一组SQL语句;

回退(rollback)指撤销指定SQL语句的过程;

提交(commit)指将未存储的SQL语句结果写入数据库表;

保留点(savepoint)指事务处理中设置的临时占位符(placeholder),你可以对它发布回退(与回退整个事务处理不同)。


28 安全管理

28.1访问控制

MySQL服务器的安全基础是:用户应该对他们需要的数据具有适当的访问权,既不能多也不能少。换句话说,用户不能对过多的数据具有过多的访问权。


28.2 管理用户

MySQL用户账号和信息存储在名为mysqlMySQL数据库中。一般不需要直接访问mysql数据库和表,但有时需要直接访问。

USE mysql;

SELECT user FROM user;


28.2.1创建用户账号

CREATE USER ben IDENTIFIED BY 'p@$$w0rd';

创建一个新用户ben账号,IDENTIFIED BY指定的口令为纯文本。

RENAME USER ben TO bforta;

重命名一个用户账号。


28.2.2删除用户账号

DROP USER bforta;


28.2.3设置访问权限

SHOW GRANTS FOR bforta;

查看用户账号的权限,USAGE表示根本没有权限。

GRANT SELECT ON crashcourse.* TO bforta;

允许用户在crashcourse.*上使用SELECT

REVOKE SELECT ON crashcourse.* FROM bforta;

GRANT的反操作为REVOKE,用它来撤销特定的权限。

GRANTREVOKE可在几个层次上控制访问权限:

-整个服务器,使用GRANT ALLREVOKE ALL;

-整个数据库,使用ON database.*;

-特定的表,使用ON database.table;

-特定的列;

-特定的存储过程。

可通过列出各权限并用逗号分隔,将多条GRANT语句串在一起,

GRANT SELECT,INSERT ON crashcourse.* TO bforta;


28.2.4 更改口令

SET PASSWORD FOR bforta = Password('n3w p@$$w0rd');


29 数据库维护

29.1 备份数据

使用命令行实用程序mysqldump转储所有数据库内容到某个外部文件。

使用MySQLBACKUP TABLESELECT INTO OUTFILE转储所有数据到某个外部文件。这两条语句都接受将要创建的系统文件名,此系统文件必须不存在,否则会出错。数

据可以用RESTORE TABLE来复原。

在进行备份前使用FLUSH TABLES语句,刷新未写数据。


29.2进行数据库维护

MySQL提供了一系列的语句,可以(应该)用来保证数据库正确和正常运行。

ANALYZE TABLE orders;

用来检查表键是否正确。

CHECK TABLE orders,orderitems;

CHECK TABLE 用来针对许多问题对表进行检查。

更多MySQL语法在《MySQL必知必会》附录D中。


体会:

找本好书,慢慢看,发觉学到的东西真不少。以前一直觉得数据库有多难,但事实上,数据库有多难?我觉得,我在大学里学的数据库有点深,而且也没有针对某个数据库。像

这类的书,可以说是浅入深出了。学会了SQL语句,下一步应该再看看MySQL的编程接口,更进一步就是看MySQL的架构,和忧化MySQL了。

暂时的学习路线是《MySQL必知必会》-〉《MySQL技术内幕》-〉《高性能MySQL》。



停下来,静下心来想想,其实人生有很多问题是可以解决的!

ps:sql常用脚本记录

sql serverupdate 表set 变量 =where 变量 =select top 100 *from 表 with(nolock)order by RecordTime desc


原创粉丝点击