3. 教程

本章通过演示如何使用mysql客户程序创造和使用一个简单的数据库,提供一个MySQL的入门教程。mysql(有时称为“终端监视器”或只是“监视”)是一个交互式程序,允许你连接一个MySQL服务器,运行查询并察看结果。mysql可以用于批模式:你预先把查询放在一个文件中,然后告诉mysql执行文件的内容。本章将介绍使用mysql的两个方法。

要想查看由mysql提供的选择项目表,可以用--help选项来调用:

shell> mysql --help

本章假定mysql已经被安装在你的机器上,并且有一个MySQL服务器可以连接。否则,请联络MySQL管理员。(如果是管理员,则需要查阅本手册的其它章节,例如第5章:数据库管理。)

本章描述建立和使用一个数据库的全过程。如果你仅仅对访问一个已经存在的数据库感兴趣,可以跳过描述怎样创建数据库及它所包含的表的章节。

由于本章是一个教程,省略了许多细节。关于这里所涉及的主题的详细信息,请查阅本手册的相关章节。

3.1. 连接与断开服务器

为了连接服务器,当调用 mysql时,通常需要提供一个 MySQL用户名并且很可能需要一个 密码。如果服务器运行在登录服务器之外的其它机器上,还需要指定主机名。联系管理员以找出进行连接所使用的参数 (即,连接的主机、用户名和使用的密码 )。知道正确的参数后,可以按照以下方式进行连接:
shell> mysql -h host -u user -p
Enter password: ********

host和user分别代表MySQL服务器运行的主机名和MySQL账户用户名。设置时替换为正确的值。********代表你的密码;当mysql显示Enter password:提示时输入它。

如果有效,你应该看见mysql>提示符后的一些介绍信息:

shell> mysql -h host -u user -p
Enter password: ********
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 25338 to server version: 5.1.2-alpha-standard
 
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
 
mysql>

mysql> 提示符告诉你mysql准备为你输入命令。

一些MySQL安装允许用户以匿名(未命名)用户连接到本地主机上运行的服务器。如果你的机器是这种情况,你应该能不带任何选项地调用mysql与该服务器连接:

shell> mysql

成功地连接后,可以在mysql>提示下输入QUIT (或\q)随时退出:

mysql> QUIT
Bye

在Unix中,也可以按control-D键断开服务器。

在下列章节的大多数例子都假设你连接到了服务器。由mysql>提示指明。

3.2. 输入查询

确保你连接上了服务器,如在先前的章节讨论的。连接上服务器并布代表选择了任何数据库,但这样就可以了。知道关于如何查询的基本知识,比马上跳至创建表、给他们装载数据并且从他们检索数据更重要。本节描述输入命令的基本原则,使用几个查询,你能尝试了解mysql是如何工作的。

这是一个简单的命令,要求服务器告诉它的版本号和当前日期。在mysql>提示输入如下命令并按回车键:

mysql> SELECT VERSION(), CURRENT_DATE;
+-----------------+--------------+
| VERSION()       | CURRENT_DATE |
+-----------------+--------------+
| 5.1.2-alpha-log | 2005-10-11   |
+-----------------+--------------+
1 row in set (0.01 sec)
mysql>

这询问说明mysql的几个方面:

·         一个命令通常由SQL语句组成,随后跟着一个分号。(有一些例外不需要分号。早先提到的QUIT是一个例子。后面我们将看到其它的例子。)

·         当发出一个命令时,mysql将它发送给服务器并显示执行结果,然后显示另一个mysql>显示它准备好接受其它命令。

·         mysql用表格(行和列)方式显示查询输出。第一行包含列的标签,随后的行是查询结果。通常,列标签是你取自数据库表的列的名字。如果你正在检索一个表达式而非表列的值(如刚才的例子),mysql用表达式本身标记列。

·         mysql显示返回了多少行,以及查询花了多长时间,它给你提供服务器性能的一个大致概念。因为他们表示时钟时间(不是 CPU或机器时间),并且因为他们受到诸如服务器负载和网络延时的影响,因此这些值是不精确的。(为了简洁,在本章其它例子中不再显示“集合中的行”。)

能够以大小写输入关键词。下列查询是等价的:

mysql> SELECT VERSION(), CURRENT_DATE;
mysql> select version(), current_date;
mysql> SeLeCt vErSiOn(), current_DATE;

这是另外一个查询,它说明你能将mysql用作一个简单的计算器:

mysql> SELECT SIN(PI()/4), (4+1)*5;
+------------------+---------+
| SIN(PI()/4)      | (4+1)*5 |
+------------------+---------+
| 0.70710678118655 |      25 |
+------------------+---------+
1 row in set (0.02 sec)

至此显示的命令是相当短的单行语句。你可以在一行上输入多条语句,只需要以一个分号间隔开各语句:

mysql> SELECT VERSION(); SELECT NOW();
+-----------------+
| VERSION()       |
+-----------------+
| 5.1.2-alpha-log |
+-----------------+
1 row in set (0.00 sec)
 
+---------------------+
| NOW()               |
+---------------------+
| 2005-10-11 15:15:00 |
+---------------------+
1 row in set (0.00 sec)

不必全在一个行内给出一个命令,较长命令可以输入到多个行中。mysql通过寻找终止分号而不是输入行的结束来决定语句在哪儿结束。(换句话说,mysql接受自由格式的输入:它收集输入行但直到看见分号才执行。)

这里是一个简单的多行语句的例子:

mysql> SELECT
    -> USER()
    -> ,
    -> CURRENT_DATE;
+---------------+--------------+
| USER()        | CURRENT_DATE |
+---------------+--------------+
| jon@localhost | 2005-10-11   |
+---------------+--------------+

在这个例子中,在输入多行查询的第一行后,要注意提示符如何从mysql>变为->,这正是mysql如何指出它没见到完整的语句并且正在等待剩余的部分。提示符是你的朋友,因为它提供有价值的反馈,如果使用该反馈,将总是知道mysql正在等待什么。

如果你决定不想执行正在输入过程中的一个命令,输入\c取消它:

mysql> SELECT
    -> USER()
    -> \c
mysql>

这里也要注意提示符,在你输入\c以后,它切换回到mysql>,提供反馈以表明mysql准备接受一个新命令。

下表显示出可以看见的各个提示符并简述它们所表示的mysql的状态:

提示符

含义

mysql>

准备好接受新命令。

->

等待多行命令的下一行。

'>

等待下一行,等待以单引号(“'”)开始的字符串的结束。

">

等待下一行,等待以双引号(“"”)开始的字符串的结束。

`>

等待下一行,等待以反斜点(‘`’)开始的识别符的结束。

/*>

等待下一行,等待以/*开始的注释的结束。

当你打算在一个单行上发出一个命令时,通常会“偶然”出现多行语句,但是没有终止分号。在这种情况中,mysql等待进一步输入:

mysql> SELECT USER()
    ->

如果出现这种情况(你认为输完了语句,但是只有一个->提示符响应),很可能mysql正在等待分号。如果你没有注意到提示符的提示,在意识到你需要做什么之前,你可能会呆坐一会儿。输入一个分号完成语句,mysql将执行:

mysql> SELECT USER()
    -> ;
+---------------+
| USER()        |
+---------------+
| jon@localhost |
+---------------+

在字符串收集期间将出现 '> 和 "> 提示符(提示MySQL正等待字符串的结束)。在MySQL中,可以写由‘'’或‘"’字符括起来的字符串 (例如,'hello'或"goodbye"),并且mysql允许输入跨越多行的字符串。当看到一个'> 或 "> 提示符时,这意味着已经输入了包含以‘'’或‘"’括号字符开始的字符串的一行,但是还没有输入终止字符串的匹配引号。这显示你粗心地省掉了一个引号字符。例如:

mysql> SELECT * FROM my_table WHERE name = 'Smith AND age < 30;
    '>

如果你输入SELECT语句,然后按Enter(回车)键并等待结果,什么都没有出现。不要惊讶,“为什么该查询这么长呢?”,注意">提示符提供的线索。它告诉你mysql期望见到一个未终止字符串的余下部分。(你看见语句中的错误吗?字符串"Smith丢掉了第二个引号。)

走到这一步,你该做什么?最简单的是取消命令。然而,在这种情况下,你不能只是输入\c,因为mysql作为它正在收集的字符串的一部分来解释它!相反,应输入关闭的引号字符(这样mysql知道你完成了字符串),然后输入\c:

mysql> SELECT * FROM my_table WHERE name = 'Smith AND age < 30;
    '> '\c
mysql>

提示符回到mysql>,显示mysql准备好接受一个新命令了。

`> 提示符类似于 '> 和">提示符,但表示你已经开始但没有结束以`> 开始的识别符。

知道'>和">提示符的含义很重要,因为如果你错误地输入一个未终止的字符串,任何后面输入的行将要被mysql忽略--包括包含QUIT的行!这可能令人相当困惑,特别是如果取消当前命令前还不知道你需要提供终止引号。

3.3. 创建并使用数据库

知道怎样输入命令,便可以访问数据库了。

假定在你的家(你的“动物园”)中有很多宠物,并且你想跟踪关于它们各种类型的信息。你可以通过创建表来保存你的数据并根据所需要的信息装载他们,然后你可以从表中检索数据来回答关于动物不同种类的问题。本节显示如何做到所有这些事情:

·         创建数据库

·         创建数据库表

·         装载数据到数据库表

·         以各种方法从表中检索数据

·         使用多个表

动物园数据库很简单(特意的),但是不难把它想象成可能用到类似数据库的真实世界情况。例如,农夫可以使用这样的一个数据库来追踪家畜,或者兽医可以用它跟踪病畜记录。从MySQL网址上可以获得后面章节中将用到的含有部分查询和样例数据的动物园分发。有tar压缩格式 (http://www.mysql.com/Downloads/Contrib/Examples/menagerie.tar.gz)和Zip压缩格式 (http://www.mysql.com/Downloads/Contrib/Examples/menagerie.zip)。

使用SHOW语句找出服务器上当前存在什么数据库:

mysql> SHOW DATABASES;
+----------+
| Database |
+----------+
| mysql    |
| test     |
| tmp      |
+----------+

可能你的机器上的数据库列表是不同的,但是很可能有mysql和test数据库。mysql是必需的,因为它描述用户访问权限,test数据库经常作为用户试身手的工作区。

请注意如果没有SHOW DATABASES权限,则不能看见所有数据库。参见13.5.1.3节,“GRANT和REVOKE语法”

如果test数据库存在,尝试访问它:

mysql> USE test
Database changed

注意,USE,类似QUIT,不需要一个分号。(如果你喜欢,你可以用一个分号终止这样的语句;这无碍)USE语句在使用上也有另外一个特殊的地方:它必须在一个单行上给出。

你可列在后面的例子中使用test数据库(如果你能访问它),但是你在该数据库创建的任何东西可以被访问它的其它人删除,因此,你应该询问MySQL管理员许可你使用自己的一个数据库。假定你想要调用你的menagerie,管理员需要执行这样一条命令:

mysql> GRANT ALL ON menagerie.* TO 'your_mysql_name'@'your_client_host';

这里your_mysql_name是分配给你的MySQL用户名,your_client_host是所连接的服务器所在的主机。

3.3.1. 创建并选择数据库

如果管理员在设置权限时为你创建了数据库,你可以开始使用它。否则,你需要自己创建数据库:
mysql> CREATE DATABASE menagerie;

在Unix下,数据库名称是区分大小写的(不像SQL关键字),因此你必须总是以menagerie访问数据库,而不能用Menagerie、MENAGERIE或其它一些变量。对表名也是这样的。(在Windows下,该限制不适用,尽管你必须在一个给定的查询中使用同样的大小写来引用数据库和表。但是,由于多种原因,作为最好的惯例,一定要使用与数据库创建时的同样的大小写。)

创建数据库并不表示选定并使用它,你必须明确地操作。为了使menagerie成为当前的数据库,使用这个命令:

mysql> USE menagerie
Database changed

数据库只需要创建一次,但是必须在每次启动mysql会话时在使用前先选择它。你可以根据上面的例子执行一个USE语句来实现。还可以在调用mysql时,通过命令行选择数据库,只需要在提供连接参数之后指定数据库名称。例如:

shell> mysql -h host -u user -p menagerie
Enter password: ********

注意,刚才显示的命令行中的menagerie是你的 密码。如果你想要在命令行上在-p选项后提供 密码,则不能插入空格(例如,如-pmypassword,不是-p mypassword)。但是,不建议在命令行输入密码,因为这样会暴露 密码,能被在机器上登录的其它用户窥探到。

3.3.2. 创建表

创建数据库是很容易的部分,但是在这时它是空的,正如SHOW TABLES将告诉你的:

mysql> SHOW TABLES;
Empty set (0.00 sec)

较难的部分是决定你的数据库结构应该是什么:你需要什么数据库表,各数据库表中有什么样的列。

你将需要一个包含你每个宠物的记录的表。它可称为pet表,并且它应该包含,最少,每个动物的名字。因为名字本身不是很有趣,表应该包含另外的信息。例如,如果在你豢养宠物的家庭有超过一个人,你可能想要列出每个动物的主人。你可能也想要记录例如种类和性别的一些基本的描述信息。

年龄呢?那可能有趣,但是存储到一个数据库中不是一件好事情。年龄随着时间流逝而变化,这意味着你将要不断地更新你的记录。相反, 存储一个固定值例如生日比较好,那么,无论何时你需要年龄,可以以当前日期和出生日期之间的差来计算它。MySQL提供了日期运算函数,因此这并不困难。存储出生日期而非年龄还有其它优点:

·         你可以使用数据库完成这样的任务,例如生成即将到来的宠物生日的提示。(如果你认为这类查询有点蠢,注意,这与从商务数据库来识别出不久要发给生日祝贺的客户是同一个问题,因为计算机帮助私人联络。)

·         你可以相对于日期而不止是当前日期来计算年龄。例如,如果你在数据库存储死亡日期,你能很容易地计算出一只宠物死时有多大。

你可能想到pet表中其它有用的其它类型信息,但是到目前为止这些已经足够了:名字、主人、种类,性别、出生和死亡日期。

使用一个CREATE TABLE语句指定你的数据库表的布局:

mysql> CREATE TABLE pet (name VARCHAR(20), owner VARCHAR(20),
    -> species VARCHAR(20), sex CHAR(1), birth DATE, death DATE);

VARCHAR适合于name、owner和species列,因为列值是变长的。这些列的长度不必都相同,而且不必是20。你可以挑选从1到65535的任何长度,从中选择一个最合理的值。(如果选择得不合适,后来证明你需要一个更长的字段,MySQL提供一个ALTER TABLE语句。)

可以用多种类型的值来表示动物记录中的性别,例如,"m"和"f",或"male"和"female"。使用单字符"m"和"f"是最简单的方法。

很显然,birth和death列应选用DATE数据类。

创建了数据库表后,SHOW TABLES应该产生一些输出:

mysql> SHOW TABLES;
+---------------------+
| Tables in menagerie |
+---------------------+
| pet                 |
+---------------------+

为了验证你的表是按你期望的方式创建,使用一个DESCRIBE语句:

mysql> DESCRIBE pet;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| name    | varchar(20) | YES  |     | NULL    |       |
| owner   | varchar(20) | YES  |     | NULL    |       |
| species | varchar(20) | YES  |     | NULL    |       |
| sex     | char(1)     | YES  |     | NULL    |       |
| birth   | date        | YES  |     | NULL    |       |
| death   | date        | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+

你可以随时使用DESCRIBE,例如,如果你忘记表中的列的名称或类型时。

3.3.3. 将数据装入表中

创建表后,需要填入内容。通过LOAD DATA和INSERT语句可以完成该任务。

假定你的宠物纪录描述如下。(假定在MySQL中期望的日期格式是YYYY-MM-DD;这可能与你习惯的不同。)

name

owner

species

sex

birth

death

Fluffy

Harold

cat

f

1993-02-04

 

Claws

Gwen

cat

m

1994-03-17

 

Buffy

Harold

dog

f

1989-05-13

 

Fang

Benny

dog

m

1990-08-27

 

Bowser

Diane

dog

m

1979-08-31

1995-07-29

Chirpy

Gwen

bird

f

1998-09-11

 

Whistler

Gwen

bird

 

1997-12-09

 

Slim

Benny

snake

m

1996-04-29

 

因为你是从一个空表开始的,填充它的一个简易方法是创建一个文本文件,每个动物各一行,然后用一个语句将文件的内容装载到表中。

你可以创建一个文本文件“pet.txt”,每行包含一个记录,用定位符(tab)把值分开,并且以CREATE TABLE语句中列出的列次序给出。对于丢失的值(例如未知的性别,或仍然活着的动物的死亡日期),你可以使用NULL值。为了在你的文本文件中表示这些内容,使用\N(反斜线,字母N)。例如,Whistler鸟的记录应为(这里值之间的空白是一个定位符):

name

owner

species

sex

birth

death

Whistler

Gwen

bird

\N

1997-12-09

\N

要想将文本文件“pet.txt”装载到pet表中,使用这个命令:

mysql> LOAD DATA LOCAL INFILE '/path/pet.txt' INTO TABLE pet;

请注意如果用Windows中的编辑器(使用\r\n做为行的结束符)创建文件,应使用:

mysql> LOAD DATA LOCAL INFILE '/path/pet.txt' INTO TABLE pet
    -> LINES TERMINATED BY '\r\n';

(在运行OS X的Apple机上,应使用行结束符'\r'。)

如果你愿意,你能明确地在LOAD DATA语句中指出列值的分隔符和行尾标记,但是默认标记是定位符和换行符。这对读入文件“pet.txt”的语句已经足够。

如果该语句失败,可能是你安装的MySQL不与使用默认值的本地文件兼容。关于如何更改请参见5.6.4节,“LOAD DATA LOCAL安全问题

如果想要一次增加一个新记录,可以使用INSERT语句。最简单的形式是,提供每一列的值,其顺序与CREATE TABLE语句中列的顺序相同。假定Diane把一只新仓鼠命名为Puffball,你可以使用下面的INSERT语句添加一条新记录:

mysql> INSERT INTO pet
    -> VALUES ('Puffball','Diane','hamster','f','1999-03-30',NULL);

注意,这里字符串和日期值均为引号扩起来的字符串。另外,可以直接用INSERT语句插入NULL代表不存在的值。不能使用LOAD DATA中所示的的\N。

从这个例子,你应该能看到涉及很多的键入用多个INSERT语句而非单个LOAD DATA语句装载你的初始记录。

3.3.4. 从表检索信息

SELECT语句用来从数据表中检索信息。语句的一般格式是:
SELECT what_to_select
FROM which_table
WHERE conditions_to_satisfy;

what_to_select指出你想要看到的内容,可以是列的一个表,或*表示“所有的列”。which_table指出你想要从其检索数据的表。WHERE子句是可选项,如果选择该项,conditions_to_satisfy指定行必须满足的检索条件。

3.3.4.1. 选择所有数据
SELECT最简单的形式是从一个表中检索所有记录:
mysql> SELECT * FROM pet;
+----------+--------+---------+------+------------+------------+
| name     | owner  | species | sex  | birth      | death      |
+----------+--------+---------+------+------------+------------+
| Fluffy   | Harold | cat     | f    | 1993-02-04 | NULL       |
| Claws    | Gwen   | cat     | m    | 1994-03-17 | NULL       |
| Buffy    | Harold | dog     | f    | 1989-05-13 | NULL       |
| Fang     | Benny  | dog     | m    | 1990-08-27 | NULL       |
| Bowser   | Diane  | dog     | m    | 1979-08-31 | 1995-07-29 |
| Chirpy   | Gwen   | bird    | f    | 1998-09-11 | NULL       |
| Whistler | Gwen   | bird    | NULL | 1997-12-09 | NULL       |
| Slim     | Benny  | snake   | m    | 1996-04-29 | NULL       |
| Puffball | Diane  | hamster | f    | 1999-03-30 | NULL       |
+----------+--------+---------+------+------------+------------+

如果你想要浏览整个表,可以使用这种形式的SELECT,例如,刚刚装载了初始数据集以后。也有可能你想到Bowser的生日看起来不很对。查阅你原来的家谱,你发现正确的出生年是1989,而不是1979。

至少有两种修正方法:

·         编辑文件“pet.txt”改正错误,然后使用DELETE和LOAD DATA清空并重新装载表:

·                mysql> DELETE FROM pet;
·                mysql> LOAD DATA LOCAL INFILE 'pet.txt' INTO TABLE pet;

然而, 如果这样操做,必须重新输入Puffball记录。

·         用一个UPDATE语句仅修正错误记录:

·                mysql> UPDATE pet SET birth = '1989-08-31' WHERE name = 'Bowser';

UPDATE只更改有问题的记录,不需要重新装载数据库表。

3.3.4.2. 选择特殊行
如上所示,检索整个表是容易的。只需要从 SELECT语句中删掉 WHERE子句。但是一般你不想看到整个表,特别地当表变得很大时。相反,你通常对回答一个具体的问题更感兴趣,在这种情况下在你想要的信息上进行一些限制。让我们看一些他们回答的有关你宠物的问题的选择查询。

可以从表中只选择特定的行。例如,如果你想要验证你对Bowser的生日所做的更改,按下述方法选择Bowser的记录:

mysql> SELECT * FROM pet WHERE name = 'Bowser';
+--------+-------+---------+------+------------+------------+
| name   | owner | species | sex  | birth      | death      |
+--------+-------+---------+------+------------+------------+
| Bowser | Diane | dog     | m    | 1989-08-31 | 1995-07-29 |
+--------+-------+---------+------+------------+------------+

输出证实正确的年份记录为1989,而不是1979。

字符串比较时通常对大小些不敏感,因此你可以将名字指定为"bowser"、"BOWSER"等,查询结果相同。

你可以在任何列上指定条件,不只仅仅是name。例如,如果你想要知道哪个动物在1998以后出生的,测试birth列:

mysql> SELECT * FROM pet WHERE birth > '1998-1-1';
+----------+-------+---------+------+------------+-------+
| name     | owner | species | sex  | birth      | death |
+----------+-------+---------+------+------------+-------+
| Chirpy   | Gwen  | bird    | f    | 1998-09-11 | NULL  |
| Puffball | Diane | hamster | f    | 1999-03-30 | NULL  |
+----------+-------+---------+------+------------+-------+

可以组合条件,例如,找出雌性的狗:

mysql> SELECT * FROM pet WHERE species = 'dog' AND sex = 'f';
+-------+--------+---------+------+------------+-------+
| name  | owner  | species | sex  | birth      | death |
+-------+--------+---------+------+------------+-------+
| Buffy | Harold | dog     | f    | 1989-05-13 | NULL  |
+-------+--------+---------+------+------------+-------+

上面的查询使用AND逻辑操作符,也有一个OR操作符:

mysql> SELECT * FROM pet WHERE species = 'snake' OR species = 'bird';
+----------+-------+---------+------+------------+-------+
| name     | owner | species | sex  | birth      | death |
+----------+-------+---------+------+------------+-------+
| Chirpy   | Gwen  | bird    | f    | 1998-09-11 | NULL  |
| Whistler | Gwen  | bird    | NULL | 1997-12-09 | NULL  |
| Slim     | Benny | snake   | m    | 1996-04-29 | NULL  |
+----------+-------+---------+------+------------+-------+

AND和OR可以混用,但AND比OR具有更高的优先级。如果你使用两个操作符,使用圆括号指明如何对条件进行分组是一个好主意:

mysql> SELECT * FROM pet WHERE (species = 'cat' AND sex = 'm')
    -> OR (species = 'dog' AND sex = 'f');
+-------+--------+---------+------+------------+-------+
| name  | owner  | species | sex  | birth      | death |
+-------+--------+---------+------+------------+-------+
| Claws | Gwen   | cat     | m    | 1994-03-17 | NULL  |
| Buffy | Harold | dog     | f    | 1989-05-13 | NULL  |
+-------+--------+---------+------+------------+-------+
3.3.4.3. 选择特殊列
如果你不想看到表中的所有行,就命名你感兴趣的列,用逗号分开。例如,如果你想要知道你的动物什么时候出生的,选择 name和 birth列:
mysql> SELECT name, birth FROM pet;
+----------+------------+
| name     | birth      |
+----------+------------+
| Fluffy   | 1993-02-04 |
| Claws    | 1994-03-17 |
| Buffy    | 1989-05-13 |
| Fang     | 1990-08-27 |
| Bowser   | 1989-08-31 |
| Chirpy   | 1998-09-11 |
| Whistler | 1997-12-09 |
| Slim     | 1996-04-29 |
| Puffball | 1999-03-30 |
+----------+------------+

找出谁拥有宠物,使用这个查询:

mysql> SELECT owner FROM pet;
+--------+
| owner  |
+--------+
| Harold |
| Gwen   |
| Harold |
| Benny  |
| Diane  |
| Gwen   |
| Gwen   |
| Benny  |
| Diane  |
+--------+

请注意该查询只是简单地检索每个记录的owner列,并且他们中的一些出现多次。为了使输出减到最少,增加关键字DISTINCT检索出每个唯一的输出记录:

mysql> SELECT DISTINCT owner FROM pet;
+--------+
| owner  |
+--------+
| Benny  |
| Diane  |
| Gwen   |
| Harold |
+--------+

可以使用一个WHERE子句结合行选择与列选择。例如,要想查询狗和猫的出生日期,使用这个查询:

mysql> SELECT name, species, birth FROM pet
    -> WHERE species = 'dog' OR species = 'cat';
+--------+---------+------------+
| name   | species | birth      |
+--------+---------+------------+
| Fluffy | cat     | 1993-02-04 |
| Claws  | cat     | 1994-03-17 |
| Buffy  | dog     | 1989-05-13 |
| Fang   | dog     | 1990-08-27 |
| Bowser | dog     | 1989-08-31 |
+--------+---------+------------+
3.3.4.4. 分类行
你可能已经注意到前面的例子中结果行没有以特定的顺序显示。然而,当行按某种方式排序时,检查查询输出通常更容易。为了排序结果,使用 ORDER BY子句。

这里是动物生日,按日期排序:

mysql> SELECT name, birth FROM pet ORDER BY birth;
+----------+------------+
| name     | birth      |
+----------+------------+
| Buffy    | 1989-05-13 |
| Bowser   | 1989-08-31 |
| Fang     | 1990-08-27 |
| Fluffy   | 1993-02-04 |
| Claws    | 1994-03-17 |
| Slim     | 1996-04-29 |
| Whistler | 1997-12-09 |
| Chirpy   | 1998-09-11 |
| Puffball | 1999-03-30 |
+----------+------------+

在字符类型列上,与所有其他比较操作类似,分类功能正常情况下是以区分大小写的方式执行的。这意味着,对于等同但大小写不同的列,并未定义其顺序。对于某一列,可以使用BINARY强制执行区分大小写的分类功能,如:ORDER BY BINARYcol_name.

默认排序是升序,最小的值在第一。要想以降序排序,在你正在排序的列名上增加DESC(降序 )关键字:

mysql> SELECT name, birth FROM pet ORDER BY birth DESC;
+----------+------------+
| name     | birth      |
+----------+------------+
| Puffball | 1999-03-30 |
| Chirpy   | 1998-09-11 |
| Whistler | 1997-12-09 |
| Slim     | 1996-04-29 |
| Claws    | 1994-03-17 |
| Fluffy   | 1993-02-04 |
| Fang     | 1990-08-27 |
| Bowser   | 1989-08-31 |
| Buffy    | 1989-05-13 |
+----------+------------+

可以对多个列进行排序,并且可以按不同的方向对不同的列进行排序。例如,按升序对动物的种类进行排序,然后按降序根据生日对各动物种类进行排序(最年轻的动物在最前面),使用下列查询:

mysql> SELECT name, species, birth FROM pet
    -> ORDER BY species, birth DESC;
+----------+---------+------------+
| name     | species | birth      |
+----------+---------+------------+
| Chirpy   | bird    | 1998-09-11 |
| Whistler | bird    | 1997-12-09 |
| Claws    | cat     | 1994-03-17 |
| Fluffy   | cat     | 1993-02-04 |
| Fang     | dog     | 1990-08-27 |
| Bowser   | dog     | 1989-08-31 |
| Buffy    | dog     | 1989-05-13 |
| Puffball | hamster | 1999-03-30 |
| Slim     | snake   | 1996-04-29 |
+----------+---------+------------+

注意DESC关键字仅适用于在它前面的列名(birth);不影响species列的排序顺序。

3.3.4.5. 日期计算

MySQL提供了几个函数,可以用来计算日期,例如,计算年龄或提取日期部分。

要想确定每个宠物有多大,可以计算当前日期的年和出生日期之间的差。如果当前日期的日历年比出生日期早,则减去一年。以下查询显示了每个宠物的出生日期、当前日期和年龄数值的年数字。

mysql> SELECT name, birth, CURDATE(),
    -> (YEAR(CURDATE())-YEAR(birth))
    -> - (RIGHT(CURDATE(),5)<RIGHT(birth,5))
    -> AS age
    -> FROM pet;
+----------+------------+------------+------+
| name     | birth      | CURDATE()  | age  |
+----------+------------+------------+------+
| Fluffy   | 1993-02-04 | 2003-08-19 |   10 |
| Claws    | 1994-03-17 | 2003-08-19 |    9 |
| Buffy    | 1989-05-13 | 2003-08-19 |   14 |
| Fang     | 1990-08-27 | 2003-08-19 |   12 |
| Bowser   | 1989-08-31 | 2003-08-19 |   13 |
| Chirpy   | 1998-09-11 | 2003-08-19 |    4 |
| Whistler | 1997-12-09 | 2003-08-19 |    5 |
| Slim     | 1996-04-29 | 2003-08-19 |    7 |
| Puffball | 1999-03-30 | 2003-08-19 |    4 |
+----------+------------+------------+------+

此处,YEAR()提取日期的年部分,RIGHT()提取日期的MM-DD (日历年)部分的最右面5个字符。比较MM-DD值的表达式部分的值一般为1或0,如果CURDATE()的年比birth的年早,则年份应减去1。整个表达式有些难懂,使用alias (age)来使输出的列标记更有意义。

尽管查询可行,如果以某个顺序排列行,则能更容易地浏览结果。添加ORDER BY name子句按照名字对输出进行排序则能够实现。

mysql> SELECT name, birth, CURDATE(),
    -> (YEAR(CURDATE())-YEAR(birth))
    -> - (RIGHT(CURDATE(),5)<RIGHT(birth,5))
    -> AS age
    -> FROM pet ORDER BY name;
+----------+------------+------------+------+
| name     | birth      | CURDATE()  | age  |
+----------+------------+------------+------+
| Bowser   | 1989-08-31 | 2003-08-19 |   13 |
| Buffy    | 1989-05-13 | 2003-08-19 |   14 |
| Chirpy   | 1998-09-11 | 2003-08-19 |    4 |
| Claws    | 1994-03-17 | 2003-08-19 |    9 |
| Fang     | 1990-08-27 | 2003-08-19 |   12 |
| Fluffy   | 1993-02-04 | 2003-08-19 |   10 |
| Puffball | 1999-03-30 | 2003-08-19 |    4 |
| Slim     | 1996-04-29 | 2003-08-19 |    7 |
| Whistler | 1997-12-09 | 2003-08-19 |    5 |
+----------+------------+------------+------+

为了按age而非name排序输出,只要再使用一个ORDER BY子句:

mysql> SELECT name, birth, CURDATE(),
    -> (YEAR(CURDATE())-YEAR(birth))
    -> - (RIGHT(CURDATE(),5)<RIGHT(birth,5))
    -> AS age
    -> FROM pet ORDER BY age;
+----------+------------+------------+------+
| name     | birth      | CURDATE()  | age  |
+----------+------------+------------+------+
| Chirpy   | 1998-09-11 | 2003-08-19 |    4 |
| Puffball | 1999-03-30 | 2003-08-19 |    4 |
| Whistler | 1997-12-09 | 2003-08-19 |    5 |
| Slim     | 1996-04-29 | 2003-08-19 |    7 |
| Claws    | 1994-03-17 | 2003-08-19 |    9 |
| Fluffy   | 1993-02-04 | 2003-08-19 |   10 |
| Fang     | 1990-08-27 | 2003-08-19 |   12 |
| Bowser   | 1989-08-31 | 2003-08-19 |   13 |
| Buffy    | 1989-05-13 | 2003-08-19 |   14 |
+----------+------------+------------+------+

可以使用一个类似的查询来确定已经死亡动物的死亡年龄。你通过检查death值是否是NULL来确定是哪些动物,然后,对于那些非NULL值的动物,需要计算出death和birth值之间的差:

mysql> SELECT name, birth, death,
    -> (YEAR(death)-YEAR(birth)) - (RIGHT(death,5)<RIGHT(birth,5))
    -> AS age
    -> FROM pet WHERE death IS NOT NULL ORDER BY age;
+--------+------------+------------+------+
| name   | birth      | death      | age  |
+--------+------------+------------+------+
| Bowser | 1989-08-31 | 1995-07-29 |    5 |
+--------+------------+------------+------+

查询使用death IS NOT NULL而非death != NULL,因为NULL是特殊的值,不能使用普通比较符来比较,以后会给出解释。参见3.3.4.6节,“NULL值操作

如果你想要知道哪个动物下个月过生日,怎么办?对于这类计算,年和天是无关的,你只需要提取birth列的月份部分。MySQL提供几个日期部分的提取函数,例如YEAR( )、MONTH( )和DAYOFMONTH( )。在这里MONTH()是适合的函数。为了看它怎样工作,运行一个简单的查询,显示birth和MONTH(birth)的值:

mysql> SELECT name, birth, MONTH(birth) FROM pet;
+----------+------------+--------------+
| name     | birth      | MONTH(birth) |
+----------+------------+--------------+
| Fluffy   | 1993-02-04 |            2 |
| Claws    | 1994-03-17 |            3 |
| Buffy    | 1989-05-13 |            5 |
| Fang     | 1990-08-27 |            8 |
| Bowser   | 1989-08-31 |            8 |
| Chirpy   | 1998-09-11 |            9 |
| Whistler | 1997-12-09 |           12 |
| Slim     | 1996-04-29 |            4 |
| Puffball | 1999-03-30 |            3 |
+----------+------------+--------------+

找出下个月生日的动物也是容易的。假定当前月是4月,那么月值是4,你可以找在5月出生的动物 (5月),方法是:

mysql> SELECT name, birth FROM pet WHERE MONTH(birth) = 5;
+-------+------------+
| name  | birth      |
+-------+------------+
| Buffy | 1989-05-13 |
+-------+------------+

如果当前月份是12月,就有点复杂了。你不能只把1加到月份数(12)上并寻找在13月出生的动物,因为没有这样的月份。相反,你应寻找在1月出生的动物(1月)。

你甚至可以编写查询,不管当前月份是什么它都能工作。采用这种方法不必在查询中使用一个特定的月份,DATE_ADD( )允许在一个给定的日期上加上时间间隔。如果在NOW( )值上加上一个月,然后用MONTH()提取月份,结果产生生日所在月份:

mysql> SELECT name, birth FROM pet
    -> WHERE MONTH(birth) = MONTH(DATE_ADD(CURDATE(),INTERVAL 1 MONTH));

完成该任务的另一个方法是加1以得出当前月份的下一个月(在使用取模函数(MOD)后,如果月份当前值是12,则“回滚”到值0):

mysql> SELECT name, birth FROM pet
    -> WHERE MONTH(birth) = MOD(MONTH(CURDATE()), 12) + 1;

注意,MONTH返回在1和12之间的一个数字,且MOD(something,12)返回在0和11之间的一个数字,因此必须在MOD( )以后加1,否则我们将从11月( 11 )跳到1月(1)。

3.3.4.6. NULL值操作

NULL值可能令人感到奇怪直到你习惯它。概念上,NULL意味着“没有值”或“未知值”,且它被看作与众不同的值。为了测试NULL,你不能使用算术比较 操作符例如=、<或!=。为了说明它,试试下列查询:

mysql> SELECT 1 = NULL, 1 <> NULL, 1 < NULL, 1 > NULL;
+----------+-----------+----------+----------+
| 1 = NULL | 1 <> NULL | 1 < NULL | 1 > NULL |
+----------+-----------+----------+----------+
|     NULL |      NULL |     NULL |     NULL |
+----------+-----------+----------+----------+

很显然你不能通过这些比较得到有意义的结果。相反使用IS NULL和IS NOT NULL操作符:

mysql> SELECT 1 IS NULL, 1 IS NOT NULL;
+-----------+---------------+
| 1 IS NULL | 1 IS NOT NULL |
+-----------+---------------+
|         0 |             1 |
+-----------+---------------+

请注意在MySQL中,0或 NULL意味着假而其它值意味着真。布尔运算的默认真值是1。

对NULL的特殊处理即是在前面的章节中,为了决定哪个动物不再是活着的,使用death IS NOT NULL而不使用death != NULL的原因。

在GROUP BY中,两个NULL值视为相同。

执行ORDER BY时,如果运行 ORDER BY ... ASC,则NULL值出现在最前面,若运行ORDER BY ... DESC,则NULL值出现在最后面。

NULL操作的常见错误是不能在定义为NOT NULL的列内插入0或空字符串,但事实并非如此。在NULL表示"没有数值"的地方有数值。使用IS[NOT] NULL则可以很容易地进行测试,如下所示:

mysql> SELECT 0 IS NULL, 0 IS NOT NULL, '' IS NULL, '' IS NOT NULL;
+-----------+---------------+------------+----------------+
| 0 IS NULL | 0 IS NOT NULL | '' IS NULL | '' IS NOT NULL |
+-----------+---------------+------------+----------------+
|         0 |             1 |          0 |              1 |
+-----------+---------------+------------+----------------+

因此完全可以在定义为NOT NULL的列内插入0或空字符串,实际是NOT NULL。参见A.5.3节,“与NULL值有关的问题

3.3.4.7. 模式匹配

MySQL提供标准的SQL模式匹配,以及一种基于象Unix实用程序如vigrepsed的扩展正则表达式模式匹配的格式。

SQL模式匹配允许你使用“_”匹配任何单个字符,而“%”匹配任意数目字符(包括零字符)。在 MySQL中,SQL的模式默认是忽略大小写的。下面给出一些例子。注意使用SQL模式时,不能使用=或!=;而应使用LIKE或NOT LIKE比较操作符。

要想找出以“b”开头的名字:

mysql> SELECT * FROM pet WHERE name LIKE 'b%';
+--------+--------+---------+------+------------+------------+
| name   | owner  | species | sex  | birth      | death      |
+--------+--------+---------+------+------------+------------+
| Buffy  | Harold | dog     | f    | 1989-05-13 | NULL       |
| Bowser | Diane  | dog     | m    | 1989-08-31 | 1995-07-29 |
+--------+--------+---------+------+------------+------------+

要想找出以“fy”结尾的名字:

mysql> SELECT * FROM pet WHERE name LIKE '%fy';
+--------+--------+---------+------+------------+-------+
| name   | owner  | species | sex  | birth      | death |
+--------+--------+---------+------+------------+-------+
| Fluffy | Harold | cat     | f    | 1993-02-04 | NULL  |
| Buffy  | Harold | dog     | f    | 1989-05-13 | NULL  |
+--------+--------+---------+------+------------+-------+

要想找出包含“w”的名字:

mysql> SELECT * FROM pet WHERE name LIKE '%w%';
+----------+-------+---------+------+------------+------------+
| name     | owner | species | sex  | birth      | death      |
+----------+-------+---------+------+------------+------------+
| Claws    | Gwen  | cat     | m    | 1994-03-17 | NULL       |
| Bowser   | Diane | dog     | m    | 1989-08-31 | 1995-07-29 |
| Whistler | Gwen  | bird    | NULL | 1997-12-09 | NULL       |
+----------+-------+---------+------+------------+------------+

要想找出正好包含5个字符的名字,使用“_”模式字符:

mysql> SELECT * FROM pet WHERE name LIKE '_____';
+-------+--------+---------+------+------------+-------+
| name  | owner  | species | sex  | birth      | death |
+-------+--------+---------+------+------------+-------+
| Claws | Gwen   | cat     | m    | 1994-03-17 | NULL  |
| Buffy | Harold | dog     | f    | 1989-05-13 | NULL  |
+-------+--------+---------+------+------------+-------+

MySQL提供的模式匹配的其它类型是使用扩展正则表达式。当你对这类模式进行匹配测试时,使用REGEXP和NOT REGEXP操作符(或RLIKE和NOT RLIKE,它们是同义词)。

扩展正则表达式的一些字符是:

·         ‘.’匹配任何单个的字符。

·         字符类“[...]”匹配在方括号内的任何字符。例如,“[abc]”匹配“a”“b”“c”。为了命名字符的范围,使用一个“-”。“[a-z]”匹配任何字母,而“[0-9]”匹配任何数字。

·         “ * ”匹配零个或多个在它前面的字符。例如,“x*”匹配任何数量的“x”字符,“[0-9]*”匹配任何数量的数字,而“.*”匹配任何数量的任何字符。

  • 如果REGEXP模式与被测试值的任何地方匹配,模式就匹配(这不同于LIKE模式匹配,只有与整个值匹配,模式才匹配)。
  • 为了定位一个模式以便它必须匹配被测试值的开始或结尾,在模式开始处使用“^”在模式的结尾用“$”

为了说明扩展正则表达式如何工作,下面使用REGEXP重写上面所示的LIKE查询:

为了找出以“b”开头的名字,使用“^”匹配名字的开始:

mysql> SELECT * FROM pet WHERE name REGEXP '^b';
+--------+--------+---------+------+------------+------------+
| name   | owner  | species | sex  | birth      | death      |
+--------+--------+---------+------+------------+------------+
| Buffy  | Harold | dog     | f    | 1989-05-13 | NULL       |
| Bowser | Diane  | dog     | m    | 1989-08-31 | 1995-07-29 |
+--------+--------+---------+------+------------+------------+

如果你想强制使REGEXP比较区分大小写,使用BINARY关键字使其中一个字符串变为二进制字符串。该查询只匹配名称首字母的小写‘b’。

mysql> SELECT * FROM pet WHERE name REGEXP BINARY '^b';

为了找出以“fy”结尾的名字,使用“$”匹配名字的结尾:

mysql> SELECT * FROM pet WHERE name REGEXP 'fy$';
+--------+--------+---------+------+------------+-------+
| name   | owner  | species | sex  | birth      | death |
+--------+--------+---------+------+------------+-------+
| Fluffy | Harold | cat     | f    | 1993-02-04 | NULL  |
| Buffy  | Harold | dog     | f    | 1989-05-13 | NULL  |
+--------+--------+---------+------+------------+-------+

为了找出包含一个“w”的名字,使用以下查询:

mysql> SELECT * FROM pet WHERE name REGEXP 'w';
+----------+-------+---------+------+------------+------------+
| name     | owner | species | sex  | birth      | death      |
+----------+-------+---------+------+------------+------------+
| Claws    | Gwen  | cat     | m    | 1994-03-17 | NULL       |
| Bowser   | Diane | dog     | m    | 1989-08-31 | 1995-07-29 |
| Whistler | Gwen  | bird    | NULL | 1997-12-09 | NULL       |
+----------+-------+---------+------+------------+------------+

既然如果一个正则表达式出现在值的任何地方,其模式匹配了,就不必在先前的查询中在模式的两侧放置一个通配符以使得它匹配整个值,就像你使用了一个SQL模式那样。

为了找出包含正好5个字符的名字,使用“^”“$”匹配名字的开始和结尾,和5个“.”实例在两者之间:

mysql> SELECT * FROM pet WHERE name REGEXP '^.....$';
+-------+--------+---------+------+------------+-------+
| name  | owner  | species | sex  | birth      | death |
+-------+--------+---------+------+------------+-------+
| Claws | Gwen   | cat     | m    | 1994-03-17 | NULL  |
| Buffy | Harold | dog     | f    | 1989-05-13 | NULL  |
+-------+--------+---------+------+------------+-------+

你也可以使用“{n}”“重复n次”操作符重写前面的查询:

mysql> SELECT * FROM pet WHERE name REGEXP '^.{5}$';
+-------+--------+---------+------+------------+-------+
| name  | owner  | species | sex  | birth      | death |
+-------+--------+---------+------+------------+-------+
| Claws | Gwen   | cat     | m    | 1994-03-17 | NULL  |
| Buffy | Harold | dog     | f    | 1989-05-13 | NULL  |
+-------+--------+---------+------+------------+-------+

附录G:MySQL正则表达式提供了关于正则表达式的句法的详细信息。

3.3.4.8. 计数行
数据库经常用于回答这个问题,“某个类型的数据在表中出现的频度 ?”例如,你可能想要知道你有多少宠物,或每位主人有多少宠物,或你可能想要对你的动物进行各种类型的普查。

计算你拥有动物的总数目与“在pet表中有多少行?”是同样的问题,因为每个宠物有一个记录。COUNT(*)函数计算行数,所以计算动物数目的查询应为:

mysql> SELECT COUNT(*) FROM pet;
+----------+
| COUNT(*) |
+----------+
|        9 |
+----------+

在前面,你检索了拥有宠物的人的名字。如果你想要知道每个主人有多少宠物,你可以使用COUNT( )函数:

mysql> SELECT owner, COUNT(*) FROM pet GROUP BY owner;
+--------+----------+
| owner  | COUNT(*) |
+--------+----------+
| Benny  |        2 |
| Diane  |        2 |
| Gwen   |        3 |
| Harold |        2 |
+--------+----------+

注意,使用GROUP BY对每个owner的所有记录分组,没有它,你会得到错误消息:

mysql> SELECT owner, COUNT(*) FROM pet;
ERROR 1140 (42000): Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) 
with no GROUP columns is illegal if there is no GROUP BY clause

COUNT( )和GROUP BY以各种方式分类你的数据。下列例子显示出进行动物普查操作的不同方式。

每种动物的数量:

mysql> SELECT species, COUNT(*) FROM pet GROUP BY species;
+---------+----------+
| species | COUNT(*) |
+---------+----------+
| bird    |        2 |
| cat     |        2 |
| dog     |        3 |
| hamster |        1 |
| snake   |        1 |
+---------+----------+

每种性别的动物数量:

mysql> SELECT sex, COUNT(*) FROM pet GROUP BY sex;
+------+----------+
| sex  | COUNT(*) |
+------+----------+
| NULL |        1 |
| f    |        4 |
| m    |        4 |
+------+----------+

(在这个输出中,NULL表示“未知性别”。)

按种类和性别组合的动物数量:

mysql> SELECT species, sex, COUNT(*) FROM pet GROUP BY species, sex;
+---------+------+----------+
| species | sex  | COUNT(*) |
+---------+------+----------+
| bird    | NULL |        1 |
| bird    | f    |        1 |
| cat     | f    |        1 |
| cat     | m    |        1 |
| dog     | f    |        1 |
| dog     | m    |        2 |
| hamster | f    |        1 |
| snake   | m    |        1 |
+---------+------+----------+

若使用COUNT( ),你不必检索整个表。例如, 前面的查询,当只对狗和猫进行时,应为:

mysql> SELECT species, sex, COUNT(*) FROM pet
    -> WHERE species = 'dog' OR species = 'cat'
    -> GROUP BY species, sex;
+---------+------+----------+
| species | sex  | COUNT(*) |
+---------+------+----------+
| cat     | f    |        1 |
| cat     | m    |        1 |
| dog     | f    |        1 |
| dog     | m    |        2 |
+---------+------+----------+

或,如果你仅需要知道已知性别的按性别的动物数目:

mysql> SELECT species, sex, COUNT(*) FROM pet
    -> WHERE sex IS NOT NULL
    -> GROUP BY species, sex;
+---------+------+----------+
| species | sex  | COUNT(*) |
+---------+------+----------+
| bird    | f    |        1 |
| cat     | f    |        1 |
| cat     | m    |        1 |
| dog     | f    |        1 |
| dog     | m    |        2 |
| hamster | f    |        1 |
| snake   | m    |        1 |
+---------+------+----------+
3.3.4.9. 使用1个以上的表
 
pet表追踪你有哪个宠物。如果你想要记录其它相关信息,例如在他们一生中看兽医或何时后代出生,你需要另外的表。这张表应该像什么呢?需要:

·         它需要包含宠物名字以便你知道每个事件属于哪个动物。

·         需要一个日期以便你知道事件是什么时候发生的。

·         需要一个描述事件的字段。

·         如果你想要对事件进行分类,则需要一个事件类型字段。

综合上述因素,event表的CREATE TABLE语句应为:

mysql> CREATE TABLE event (name VARCHAR(20), date DATE,
    -> type VARCHAR(15), remark VARCHAR(255));

对于pet表,最容易的方法是创建包含信息的用定位符分隔的文本文件来装载初始记录:

name

date

type

remark

Fluffy

1995-05-15

litter

4 kittens, 3 female, 1 male

Buffy

1993-06-23

litter

5 puppies, 2 female, 3 male

Buffy

1994-06-19

litter

3 puppies, 3 female

Chirpy

1999-03-21

vet

needed beak straightened

Slim

1997-08-03

vet

broken rib

Bowser

1991-10-12

kennel

 

Fang

1991-10-12

kennel

 

Fang

1998-08-28

birthday

Gave him a new chew toy

Claws

1998-03-17

birthday

Gave him a new flea collar

Whistler

1998-12-09

birthday

First birthday

采用如下方式装载记录:

mysql> LOAD DATA LOCAL INFILE 'event.txt' INTO TABLE event;

根据你从已经运行在pet表上的查询中学到的,你应该能执行对event表中记录的检索;原理是一样的。但是什么时候event表本身不能回答你可能问的问题呢?

当他们有了一窝小动物时,假定你想要找出每只宠物的年龄。我们前面看到了如何通过两个日期计算年龄。event表中有母亲的生产日期,但是为了计算母亲的年龄,你需要她的出生日期,存储在pet表中。说明查询需要两个表:

mysql> SELECT pet.name,
    -> (YEAR(date)-YEAR(birth)) - (RIGHT(date,5)<RIGHT(birth,5)) AS age,
    -> remark
    -> FROM pet, event
    -> WHERE pet.name = event.name AND event.type = 'litter';
+--------+------+-----------------------------+
| name   | age  | remark                      |
+--------+------+-----------------------------+
| Fluffy |    2 | 4 kittens, 3 female, 1 male |
| Buffy  |    4 | 5 puppies, 2 female, 3 male |
| Buffy  |    5 | 3 puppies, 3 female         |
+--------+------+-----------------------------+

关于该查询要注意的几件事情:

  • FROM子句列出两个表,因为查询需要从两个表提取信息。
  • 当从多个表组合(联结)信息时,你需要指定一个表中的记录怎样能匹配其它表的记录。这很简单,因为它们都有一个name列。查询使用WHERE子句基于name值来匹配2个表中的记录。
  • 因为name列出现在两个表中,当引用列时,你一定要指定哪个表。把表名附在列名前即可以实现。

你不必有2个不同的表来进行联结。如果你想要将一个表的记录与同一个表的其它记录进行比较,可以将一个表联结到自身。例如,为了在你的宠物之中繁殖配偶,你可以用pet联结自身来进行相似种类的雄雌配对:

 

mysql> SELECT p1.name, p1.sex, p2.name, p2.sex, p1.species
    -> FROM pet AS p1, pet AS p2
    -> WHERE p1.species = p2.species AND p1.sex = 'f' AND p2.sex = 'm';
+--------+------+--------+------+---------+
| name   | sex  | name   | sex  | species |
+--------+------+--------+------+---------+
| Fluffy | f    | Claws  | m    | cat     |
| Buffy  | f    | Fang   | m    | dog     |
| Buffy  | f    | Bowser | m    | dog     |
+--------+------+--------+------+---------+

在这个查询中,我们为表名指定别名以便能引用列并且使得每一个列引用与哪个表实例相关联更直观。

3.4. 获得数据库和表的信息

如果你忘记数据库或表的名字,或给定的表的结构是什么 (例如,它的列叫什么 ),怎么办? MySQL通过提供数据库及其支持的表的信息的几个语句解决这个问题。

你已经见到了SHOW DATABASES,它列出由服务器管理的数据库。为了找出当前选择了哪个数据库,使用DATABASE( )函数:

mysql> SELECT DATABASE();
+------------+
| DATABASE() |
+------------+
| menagerie  |
+------------+

如果你还没选择任何数据库,结果是NULL。

为了找出当前的数据库包含什么表(例如,当你不能确定一个表的名字),使用这个命令:

mysql> SHOW TABLES;
+---------------------+
| Tables in menagerie |
+---------------------+
| event               |
| pet                 |
+---------------------+

如果你想要知道一个表的结构,可以使用DESCRIBE命令;它显示表中每个列的信息:

mysql> DESCRIBE pet;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| name    | varchar(20) | YES  |     | NULL    |       |
| owner   | varchar(20) | YES  |     | NULL    |       |
| species | varchar(20) | YES  |     | NULL    |       |
| sex     | char(1)     | YES  |     | NULL    |       |
| birth   | date        | YES  |     | NULL    |       |
| death   | date        | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+

Field显示列名字,Type是列的数据类型,Null表示列是否能包含NULL值,Key显示列是否被索引而Default指定列的默认值。

如果表有索引,SHOW INDEX FROM tbl_name生成有关索引的信息。

3.5. 在批处理模式下使用mysql

在前面的章节中,你交互式地使用 mysql输入查询并且查看结果。你也可以以批模式运行 mysql。为了做到这些,把你想要运行的命令放在一个文件中,然后告诉 mysql从文件读取它的输入:
shell> mysql < batch-file

如果在Windows下运行mysql,并且文件中有一些可以造成问题的特殊字符,可以这样操作:

C:\> mysql -e "source batch-file"

如果你需要在命令行上指定连接参数,命令应为:

shell> mysql -h host -u user -p < batch-file
Enter password: ********

当这样操作mysql时,则创建一个脚本文件,然后执行脚本。

如果你想在语句出现错误的时候仍想继续执行脚本,则应使用--force命令行选项。

为什么要使用一个脚本?有很多原因:

  • 如果你需要重复运行查询(比如说,每天或每周),可以把它编成一个脚本,则每次执行时不必重新键入。
  • 可以通过拷贝并编辑脚本文件从类似的现有的查询生成一个新查询。
  • 当你正在开发查询时,批模式也是很有用的,特别对多行命令或多语句命令序列。如果你犯了一个错误,你不必重新输入所有内容,只需要编辑脚本来改正错误,然后告诉mysql再次执行脚本。
  • 如果你有一个产生多个输出的查询,你可以通过一个分页器而不是盯着它翻屏到屏幕的顶端来运行输出:
·                shell> mysql < batch-file | more
  • 你可以捕捉文件中的输出以便进行进一步的处理:
·                shell> mysql < batch-file > mysql.out
  • 你可以将脚本分发给另外的人,以便他们也能运行命令。
  • 某些情况不允许交互地使用,例如, 当你从一个cron任务中运行查询时。在这种情况下,你必须使用批模式。

当你以批模式运行mysql时,比起你交互地使用它时,其默认输出格式是不同的(更简明些)。例如,当交互式运行SELECT DISTINCT species FROM pet时,输出应为:

 

+---------+
| species |
+---------+
| bird    |
| cat     |
| dog     |
| hamster |
| snake   |
+---------+

但是当以批模式运行时,输出应为:

species
bird
cat
dog
hamster
snake

如果你想要在批模式中得到交互输出格式,使用mysql -t。为了回显以输出被执行的命令,使用mysql -vvv。

你还可以使用源代码或 \.命令从mysql提示符运行脚本:

mysql> source filename;
mysql> \. filename

3.6. 常用查询的例子

下面是一些学习如何用MySQL解决一些常见问题的例子。

在一些例子中,使用数据库表“shop”来储存某个商人(经销商)的每件物品(物品号)的价格。假定每个商人对每项物品有一个固定价格,那么(物品,商人)即为该记录的主关键字。

启动命令行工具mysql并选择数据库:

shell> mysql your-database-name

(在大多数MySQL中,你可以使用test数据库)。

你可以使用以下语句创建示例表:

mysql> CREATE TABLE shop (
    -> article INT(4) UNSIGNED ZEROFILL DEFAULT '0000' NOT NULL,
    -> dealer  CHAR(20)                 DEFAULT ''     NOT NULL,
    -> price   DOUBLE(16,2)             DEFAULT '0.00' NOT NULL,
    -> PRIMARY KEY(article, dealer));
mysql> INSERT INTO shop VALUES
    -> (1,'A',3.45),(1,'B',3.99),(2,'A',10.99),(3,'B',1.45),
    -> (3,'C',1.69),(3,'D',1.25),(4,'D',19.95);

执行语句后,表应包含以下内容:

mysql> SELECT * FROM shop;
+---------+--------+-------+
| article | dealer | price |
+---------+--------+-------+
|    0001 | A      |  3.45 |
|    0001 | B      |  3.99 |
|    0002 | A      | 10.99 |
|    0003 | B      |  1.45 |
|    0003 | C      |  1.69 |
|    0003 | D      |  1.25 |
|    0004 | D      | 19.95 |
+---------+--------+-------+

3.6.1. 列的最大值

“最大的物品号是什么?”

SELECT MAX(article) AS article FROM shop;

+---------+
| article |
+---------+
|       4 |
+---------+

3.6.2. 拥有某个列的最大值的行

任务:找出最贵物品的编号、销售商和价格。

这很容易用一个子查询做到:

SELECT article, dealer, price
FROM   shop
WHERE  price=(SELECT MAX(price) FROM shop);

另一个解决方案是按价格降序排序所有行并用MySQL特定LIMIT子句只得到第一行:

SELECT article, dealer, price
FROM shop
ORDER BY price DESC
LIMIT 1;

:如果有多项最贵的物品( 例如每个的价格为19.95),LIMIT解决方案仅仅显示其中一个!

3.6.3. 列的最大值:按组

任务:每项物品的的最高价格是多少?

SELECT article, MAX(price) AS price
FROM   shop
GROUP BY article

+---------+-------+
| article | price |
+---------+-------+
|    0001 |  3.99 |
|    0002 | 10.99 |
|    0003 |  1.69 |
|    0004 | 19.95 |
+---------+-------+

3.6.4. 拥有某个字段的组间最大值的行

任务:对每项物品,找出最贵价格的物品的经销商。

可以用这样一个子查询解决该问题:

SELECT article, dealer, price
FROM   shop s1
WHERE  price=(SELECT MAX(s2.price)
              FROM shop s2
              WHERE s1.article = s2.article);

3.6.5. 使用用户变量

你可以清空MySQL用户变量以记录结果,不必将它们保存到客户端的临时变量中。(参见 9.3节,“用户变量”.)。

例如,要找出价格最高或最低的物品的,其方法是:

mysql> SELECT @min_price:=MIN(price),@max_price:=MAX(price) FROM shop;
mysql> SELECT * FROM shop WHERE price=@min_price OR price=@max_price;
+---------+--------+-------+
| article | dealer | price |
+---------+--------+-------+
|    0003 | D      |  1.25 |
|    0004 | D      | 19.95 |
+---------+--------+-------+

3.6.6. 使用外键

在MySQL中,InnoDB表支持对外部关键字约束条件的检查。参见15.2节,“InnoDB存储引擎”。还可以参见1.8.5.5节,“外键”

只是联接两个表时,不需要外部关键字。对于除InnoDB类型的表,当使用REFERENCES tbl_name(col_name)子句定义列时可以使用外部关键字,该子句没有实际的效果,只作为备忘录或注释来提醒,你目前正定义的列指向另一个表中的一个列。执行该语句时,实现下面很重要:

·         MySQL不执行表tbl_name中的动作,例如作为你正定义的表中的行的动作的响应而删除行;换句话说,该句法不会致使ON DELETE或ON UPDATE行为(如果你在REFERENCES子句中写入ON DELETE或ON UPDATE子句,将被忽略)。

·         该句法可以创建一个column;但不创建任何索引或关键字。

·         如果用该句法定义InnoDB表,将会导致错误。

你可以使用作为联接列创建的列,如下所示:

CREATE TABLE person (
    id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
    name CHAR(60) NOT NULL,
    PRIMARY KEY (id)
);
 
CREATE TABLE shirt (
    id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
    style ENUM('t-shirt', 'polo', 'dress') NOT NULL,
    color ENUM('red', 'blue', 'orange', 'white', 'black') NOT NULL,
    owner SMALLINT UNSIGNED NOT NULL REFERENCES person(id),
    PRIMARY KEY (id)
);
 
INSERT INTO person VALUES (NULL, 'Antonio Paz');
 
SELECT @last := LAST_INSERT_ID();
 
INSERT INTO shirt VALUES
(NULL, 'polo', 'blue', @last),
(NULL, 'dress', 'white', @last),
(NULL, 't-shirt', 'blue', @last);
 
INSERT INTO person VALUES (NULL, 'Lilliana Angelovska');
 
SELECT @last := LAST_INSERT_ID();
 
INSERT INTO shirt VALUES
(NULL, 'dress', 'orange', @last),
(NULL, 'polo', 'red', @last),
(NULL, 'dress', 'blue', @last),
(NULL, 't-shirt', 'white', @last);
 
SELECT * FROM person;
+----+---------------------+
| id | name                |
+----+---------------------+
|  1 | Antonio Paz         |
|  2 | Lilliana Angelovska |
+----+---------------------+
 
SELECT * FROM shirt;
+----+---------+--------+-------+
| id | style   | color  | owner |
+----+---------+--------+-------+
|  1 | polo    | blue   |     1 |
|  2 | dress   | white  |     1 |
|  3 | t-shirt | blue   |     1 |
|  4 | dress   | orange |     2 |
|  5 | polo    | red    |     2 |
|  6 | dress   | blue   |     2 |
|  7 | t-shirt | white  |     2 |
+----+---------+--------+-------+
 
 
SELECT s.* FROM person p, shirt s
 WHERE p.name LIKE 'Lilliana%'
   AND s.owner = p.id
   AND s.color <> 'white';
 
+----+-------+--------+-------+
| id | style | color  | owner |
+----+-------+--------+-------+
|  4 | dress | orange |     2 |
|  5 | polo  | red    |     2 |
|  6 | dress | blue   |     2 |
+----+-------+--------+-------+

按照这种方式使用,REFERENCES子句不会显示在SHOW CREATE TABLE或DESCRIBE的输出中:

SHOW CREATE TABLE shirt\G
*************************** 1. row ***************************
Table: shirt
Create Table: CREATE TABLE `shirt` (
`id` smallint(5) unsigned NOT NULL auto_increment,
`style` enum('t-shirt','polo','dress') NOT NULL,
`color` enum('red','blue','orange','white','black') NOT NULL,
`owner` smallint(5) unsigned NOT NULL,
PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1

在列定义中,按这种方式使用REFERENCES作为注释或“提示”适用于表MyISAM和BerkeleyDB。

3.6.7. 根据两个键搜索

可以充分利用使用单关键字的OR子句,如同AND的处理。

一个比较灵活的例子是寻找两个通过OR组合到一起的关键字:

SELECT field1_index, field2_index FROM test_table
WHERE field1_index = '1' OR  field2_index = '1'

该情形是已经优化过的。参见7.2.6节,“索引合并优化”

还可以使用UNION将两个单独的SELECT语句的输出合成到一起来更有效地解决该问题。参见13.2.7.2节,“UNION语法

每个SELECT只搜索一个关键字,可以进行优化:

SELECT field1_index, field2_index
    FROM test_table WHERE field1_index = '1'
UNION
SELECT field1_index, field2_index
    FROM test_table WHERE field2_index = '1';

3.6.8. 根据天计算访问量

下面的例子显示了如何使用位组函数来计算每个月中用户访问网页的天数。

CREATE TABLE t1 (year YEAR(4), month INT(2) UNSIGNED ZEROFILL,
             day INT(2) UNSIGNED ZEROFILL);
INSERT INTO t1 VALUES(2000,1,1),(2000,1,20),(2000,1,30),(2000,2,2),
            (2000,2,23),(2000,2,23);

示例表中含有代表用户访问网页的年-月-日值。可以使用以下查询来确定每个月的访问天数:

SELECT year,month,BIT_COUNT(BIT_OR(1<<day)) AS days FROM t1
       GROUP BY year,month;

将返回:

+------+-------+------+
| year | month | days |
+------+-------+------+
| 2000 |    01 |    3 |
| 2000 |    02 |    2 |
+------+-------+------+

该查询计算了在表中按年/月组合的不同天数,可以自动去除重复的询问。

3.6.9. 使用AUTO_INCREMENT

可以通过AUTO_INCREMENT属性为新的行产生唯一的标识:

CREATE TABLE animals (
     id MEDIUMINT NOT NULL AUTO_INCREMENT,
     name CHAR(30) NOT NULL,
     PRIMARY KEY (id)
 );
 
INSERT INTO animals (name) VALUES 
    ('dog'),('cat'),('penguin'),
    ('lax'),('whale'),('ostrich');
 
SELECT * FROM animals;

将返回:

+----+---------+
| id | name    |
+----+---------+
|  1 | dog     |
|  2 | cat     |
|  3 | penguin |
|  4 | lax     |
|  5 | whale   |
|  6 | ostrich |
+----+---------+

你可以使用LAST_INSERT_ID()SQL函数或mysql_insert_id() C API函数来查询最新的AUTO_INCREMENT值。这些函数与具体连接有关,因此其返回值不会被其它执行插入功能的连接影响。

注释:对于多行插入,LAST_INSERT_ID()和mysql_insert_id()从插入的第一行实际返回AUTO_INCREMENT关键字。在复制设置中,通过该函数可以在其它服务器上正确复制多行插入。

对于MyISAM和BDB表,你可以在第二栏指定AUTO_INCREMENT以及多列索引。此时,AUTO_INCREMENT列生成的值的计算方法为:MAX(auto_increment_column) + 1 WHERE prefix=given-prefix。如果想要将数据放入到排序的组中可以使用该方法。

CREATE TABLE animals (
    grp ENUM('fish','mammal','bird') NOT NULL,
    id MEDIUMINT NOT NULL AUTO_INCREMENT,
    name CHAR(30) NOT NULL,
    PRIMARY KEY (grp,id)
);
 
INSERT INTO animals (grp,name) VALUES 
    ('mammal','dog'),('mammal','cat'),
    ('bird','penguin'),('fish','lax'),('mammal','whale'),
    ('bird','ostrich');
 
SELECT * FROM animals ORDER BY grp,id;

将返回:

+--------+----+---------+
| grp    | id | name    |
+--------+----+---------+
| fish   |  1 | lax     |
| mammal |  1 | dog     |
| mammal |  2 | cat     |
| mammal |  3 | whale   |
| bird   |  1 | penguin |
| bird   |  2 | ostrich |
+--------+----+---------+

请注意在这种情况下(AUTO_INCREMENT列是多列索引的一部分),如果你在任何组中删除有最大AUTO_INCREMENT值的行,将会重新用到AUTO_INCREMENT值。对于MyISAM表也如此,对于该表一般不重复使用AUTO_INCREMENT值。

如果AUTO_INCREMENT列是多索引的一部分,MySQL将使用该索引生成以AUTO_INCREMENT列开始的序列值。。例如,如果animals表含有索引PRIMARY KEY (grp, id)和INDEX(id),MySQL生成序列值时将忽略PRIMARY KEY。结果是,该表包含一个单个的序列,而不是符合grp值的序列。

要想以AUTO_INCREMENT值开始而不是1,你可以通过CREATE TABLE或ALTER TABLE来设置该值,如下所示:

mysql> ALTER TABLE tbl AUTO_INCREMENT = 100;

关于AUTO_INCREMENT的详细信息:

·         如何为列指定AUTO_INCREMENT属性:13.1.5节,“CREATE TABLE语法”13.1.2节,“ALTER TABLE语法”

·         AUTO_INCREMENT的动作取决于SQL模式:5.3.2节,“SQL服务器模式”

·         找出含有最新AUTO_INCREMENT值的行:12.1.3节,“比较函数和操作符”

·         设置将用到的AUTO_INCREMENT值: 13.5.3节,“SET语法”

·         AUTO_INCREMENT和复制:6.7节,“复制特性和已知问题”.

·         AUTO_INCREMENT相关的可用于复制的Server-system变量(auto_increment_increment和auto_increment_offset):5.3.3节,“服务器系统变量”

3.7. 孪生项目的查询

这个项目是Institute of Environmental Medicine at Karolinska Institutet Stockholm和 the Section on Clinical Research in Aging and Psychology at the University of Southern California的合作项目。

该项目包括筛选部分,即通过电话回访在瑞典超过 65 岁的所有孪生。满足某种标准的孪生进入下一阶段。在下一阶段中,医生/护士小组将访问想参加的孪生。部分检查包括物理检查和神经、心理检查、实验室试验、神经成像、心理状况评估和家族历史搜集。并且,应根据医疗和环境风险因素来搜集数据。

可从以下链接找到孪生研究的更多信息:

http://www.mep.ki.se/twinreg/index_en.html

用一个用Perl和MySQL编写的web接口来管理项目的后面部分。

每天晚上所有会谈的数据被移入一个MySQL数据库。

3.7.1. 查找所有未分发的孪生项

下列查询用来决定谁进入项目的第二部分:

SELECT
    CONCAT(p1.id, p1.tvab) + 0 AS tvid,
    CONCAT(p1.christian_name, ' ', p1.surname) AS Name,
    p1.postal_code AS Code,
    p1.city AS City,
    pg.abrev AS Area,
    IF(td.participation = 'Aborted', 'A', ' ') AS A,
    p1.dead AS dead1,
    l.event AS event1,
    td.suspect AS tsuspect1,
    id.suspect AS isuspect1,
    td.severe AS tsevere1,
    id.severe AS isevere1,
    p2.dead AS dead2,
    l2.event AS event2,
    h2.nurse AS nurse2,
    h2.doctor AS doctor2,
    td2.suspect AS tsuspect2,
    id2.suspect AS isuspect2,
    td2.severe AS tsevere2,
    id2.severe AS isevere2,
    l.finish_date
FROM
    twin_project AS tp
    /* For Twin 1 */
    LEFT JOIN twin_data AS td ON tp.id = td.id
              AND tp.tvab = td.tvab
    LEFT JOIN informant_data AS id ON tp.id = id.id
              AND tp.tvab = id.tvab
    LEFT JOIN harmony AS h ON tp.id = h.id
              AND tp.tvab = h.tvab
    LEFT JOIN lentus AS l ON tp.id = l.id
              AND tp.tvab = l.tvab
    /* For Twin 2 */
    LEFT JOIN twin_data AS td2 ON p2.id = td2.id
              AND p2.tvab = td2.tvab
    LEFT JOIN informant_data AS id2 ON p2.id = id2.id
              AND p2.tvab = id2.tvab
    LEFT JOIN harmony AS h2 ON p2.id = h2.id
              AND p2.tvab = h2.tvab
    LEFT JOIN lentus AS l2 ON p2.id = l2.id
              AND p2.tvab = l2.tvab,
    person_data AS p1,
    person_data AS p2,
    postal_groups AS pg
WHERE
    /* p1 gets main twin and p2 gets his/her twin. */
    /* ptvab is a field inverted from tvab */
    p1.id = tp.id AND p1.tvab = tp.tvab AND
    p2.id = p1.id AND p2.ptvab = p1.tvab AND
    /* Just the screening survey */
    tp.survey_no = 5 AND
    /* Skip if partner died before 65 but allow emigration (dead=9) */
    (p2.dead = 0 OR p2.dead = 9 OR
     (p2.dead = 1 AND
      (p2.death_date = 0 OR
       (((TO_DAYS(p2.death_date) - TO_DAYS(p2.birthday)) / 365)
        >= 65))))
    AND
    (
    /* Twin is suspect */
    (td.future_contact = 'Yes' AND td.suspect = 2) OR
    /* Twin is suspect - Informant is Blessed */
    (td.future_contact = 'Yes' AND td.suspect = 1
                               AND id.suspect = 1) OR
    /* No twin - Informant is Blessed */
    (ISNULL(td.suspect) AND id.suspect = 1
                        AND id.future_contact = 'Yes') OR
    /* Twin broken off - Informant is Blessed */
    (td.participation = 'Aborted'
     AND id.suspect = 1 AND id.future_contact = 'Yes') OR
    /* Twin broken off - No inform - Have partner */
    (td.participation = 'Aborted' AND ISNULL(id.suspect)
                                  AND p2.dead = 0))
    AND
    l.event = 'Finished'
    /* Get at area code */
    AND SUBSTRING(p1.postal_code, 1, 2) = pg.code
    /* Not already distributed */
    AND (h.nurse IS NULL OR h.nurse=00 OR h.doctor=00)
    /* Has not refused or been aborted */
    AND NOT (h.status = 'Refused' OR h.status = 'Aborted'
    OR h.status = 'Died' OR h.status = 'Other')
ORDER BY
    tvid;

一些解释:

·         CONCAT(p1.id, p1.tvab) + 0 AS tvid

我们想要在id和tvab的连接上以数字顺序排序。结果加0使得MySQL把结果变为一个数字。

·         列id

这标识一对孪生。它是所有表中的一个键。

·         列tvab

这标识孪生中的一个。它的值为1或2。

·         列ptvab

这是tvab的一个逆运算。当tvab是1,它是2,反之亦然。它用来保存输入并且使MySQL的优化查询更容易。

这个查询表明,怎样用联结(p1和p2)从同一个表中查找表。在例子中,这被用来检查孪生的一个是否在65岁前死了。如果如此,行不返回值。

上述所有孪生信息存在于所有表中。我们对id,tvab(所有表)和id,ptvab (person_data)上采用键以使查询更快。

在我们的生产机器上(一台200MHz UltraSPARC),这个查询返回大约 150-200行并且时间不超过一秒。

行数

person_data

71074

lentus

5291

twin_project

5286

twin_data

2012

informant_data

663

harmony

381

postal_groups

100

3.7.2. 显示孪生对状态的表

每一次会面以一个称为 event的状态码结束。下面显示的查询被用来显示按事件组合的所有孪生的表。这表明多少对孪生已经完成,多少对的其中之一已完成而另一个拒绝了,等等。
SELECT
        t1.event,
        t2.event,
        COUNT(*)
FROM
        lentus AS t1,
        lentus AS t2,
        twin_project AS tp
WHERE
        /* We are looking at one pair at a time */
        t1.id = tp.id
        AND t1.tvab=tp.tvab
        AND t1.id = t2.id
        /* Just the screening survey */
        AND tp.survey_no = 5
        /* This makes each pair only appear once */
        AND t1.tvab='1' AND t2.tvab='2'
GROUP BY
        t1.event, t2.event;

3.8. 与Apache一起使用MySQL

还有一些项目,你可以从 MySQL数据库鉴别用户,并且你还可以将日志文件写入 MySQL数据库表。

你可以将以下内容放到Apache配置文件中,更改Apache日志格式,使MySQL更容易读取:

LogFormat \
        "\"%h\",%{%Y%m%d%H%M%S}t,%>s,\"%b\",\"%{Content-Type}o\",  \
        \"%U\",\"%{Referer}i\",\"%{User-Agent}i\""

要想将该格式的日志文件装载到MySQL,你可以使用以下语句:

LOAD DATA INFILE '/local/access_log' INTO TABLE tbl_name
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '\\'

所创建的表中的列应与写入日志文件的LogFormat行对应。


这是MySQL参考手册的翻译版本,关于MySQL参考手册,请访问dev.mysql.com。 原始参考手册为英文版,与英文版参考手册相比,本翻译版可能不是最新的。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
前言 1. 一般信息 1.1. 关于本手册 1.2. 本手册采用的惯例 1.3. MySQL AB概述 1.4. MySQL数据库管理系统概述 1.4.1. MySQL的历史 1.4.2. MySQL的的主要特性 1.4.3. MySQL稳定性 1.4.4. MySQL表最大能达到多少 1.4.5. 2000年兼容性 1.5. MaxDB数据库管理系统概述 1.5.1. 什么是MaxDB? 1.5.2. MaxDB的历史 1.5.3. MaxDB的特性 1.5.4. 许可和支持 1.5.5. MaxDB和MySQL之间的特性差异 1.5.6. MaxDB和MySQL之间的协同性 1.5.7. 与MaxDB有关的链接 1.6. MySQL发展大事记 1.6.1. MySQL 5.1的新特性 1.7. MySQL信息源 1.7.1. MySQL邮件列表 1.7.2. IRC(在线聊天系统)上的MySQL社区支持 1.7.3. MySQL论坛上的MySQL社区支持 1.8. MySQL标准的兼容性 1.8.1. MySQL遵从的标准是什么 1.8.2. 选择SQL模式 1.8.3. 在ANSI模式下运行MySQL 1.8.4. MySQL对标准SQL的扩展 1.8.5. MySQL与标准SQL的差别 1.8.6. MySQL处理约束的方式 2. 安装MySQL 2.1. 一般安装问题 2.1.1. MySQL支持的操作系统 2.1.2. 选择要安装的MySQL分发版 2.1.3. 怎样获得MySQL 2.1.4. 通过MD5校验和或GnuPG验证软件包的完整性 2.1.5. 安装布局 2.2. 使用二进制分发版的标准MySQL安装 2.3. 在Windows上安装MySQL 2.3.1. Windows系统要求 2.3.2. 选择安装软件包 2.3.3. 用自动安装器安装MySQL 2.3.4. 使用MySQL安装向导 2.3.5. 使用配置向导 2.3.6. 通过非安装Zip文件安装MySQL 2.3.7. 提取安装档案文件 2.3.8. 创建选项文件 2.3.9. 选择MySQL服务器类型 2.3.10. 首次启动服务器 2.3.11. 从Windows命令行启动MySQL 2.3.12. 以Windows服务方式启动MySQL 2.3.13. 测试MySQL安装 2.3.14. 在Windows环境下对MySQL安装的故障诊断与排除 2.3.15. 在Windows下升级MySQL 2.3.16. Windows版MySQL同Unix版MySQL对比 2.4. 在Linux下安装MySQL 2.5.在Mac OS X中安装MySQL 2.6. 在NetWare中安装MySQL 2.7. 在其它类Unix系统中安装MySQL 2.8. 使用源码分发版安装MySQL 2.8.1. 源码安装概述 2.8.2. 典型配置选项 2.8.3. 从开发源码树安装 2.8.4. 处理MySQL编译问题 2.8.5. MIT-pthreads注意事项 2.8.6. 在Windows下从源码安装MySQL 2.8.7. 在Windows下编译MySQL客户端 2.9. 安装后的设置和测试 2.9.1. Windows下安装后的过程 2.9.2. Unix下安装后的过程 2.9.3. 使初始MySQL账户安全 2.10. 升级MySQL 2.10.1. 从5.0版升级 2.10.2. 升级授权表 2.10.3. 将MySQL数据库拷贝到另一台机器 2.11. 降级MySQL 2.12. 具体操作系统相关的注意事项 2.12.1. Linux注意事项 2.12.2. Mac OS X注意事项 2.12.3. Solaris注意事项 2.12.4. BSD注意事项 2.12.5. 其它Unix注意事项 2.12.6. OS/2注意事项 2.13. Perl安装注意事项 2.13.1. 在Unix中安装Perl 2.13.2. 在Windows下安装ActiveState Perl 2.13.3. 使用Perl DBI/DBD接口的问题 3. 教程 3.1. 连接与断开服务器 3.2. 输入查询 3.3. 创建并使用数据库 3.3.1. 创建并选择数据库 3.3.2. 创建表 3.3.3. 将数据装入表中 3.3.4. 从表检索信息 3.4. 获得数据库和表的信息 3.5. 在批处理模式下使用mysql 3.6. 常用查询的例子 3.6.1. 列的最大 3.6.2. 拥有某个列的最大的行 3.6.3. 列的最大:按组 3.6.4. 拥有某个字段的组间最大的行 3.6.5. 使用用户变量 3.6.6. 使用外键 3.6.7. 根据两个键搜索 3.6.8. 根据天计算访问量 3.6.9. 使用AUTO_INCREMENT 3.7. 孪生项目的查询 3.7.1. 查找所有未分发的孪生项 3.7.2. 显示孪生对状态的表 3.8. 与Apache一起使用MySQL 4. MySQL程序概述 4.1. MySQL程序概述 4.2. 调用MySQL程序 4.3. 指定程序选项 4.3.1. 在命令行上使用选项 4.3.2. 使用选项文件 4.3.3. 用环境变量指定选项 4.3.4. 使用选项设置程序变量 5. 数据库管理 5.1. MySQL服务器和服务器启动脚本 5.1.1. 服务器端脚本和实用工具概述 5.1.2. mysqld-max扩展MySQL服务器 5.1.3. mysqld_safe:MySQL服务器启动脚本 5.1.4. mysql.server:MySQL服务器启动脚本 5.1.5. mysqld_multi:管理多个MySQL服务器的程序 5.2. mysqlmanager:MySQL实例管理器 5.2.1. 用MySQL实例管理器启动MySQL服务器 5.2.2. 连接到MySQL实例管理器并创建用户账户 5.2.3. MySQL实例管理器命令行选项 5.2.4. MySQL实例管理器配置文件 5.2.5. MySQL实例管理器识别的命令 5.3. mysqld:MySQL服务器 5.3.1. mysqld命令行选项 5.3.2. SQL服务器模式 5.3.3. 服务器系统变量 5.3.4. 服务器状态变量 5.4. mysql_fix_privilege_tables:升级MySQL系统表 5.5. MySQL服务器关机进程 5.6. 一般安全问题 5.6.1. 通用安全指南 5.6.2. 使MySQL在攻击者面前保持安全 5.6.3. Mysqld安全相关启动选项 5.6.4. LOAD DATA LOCAL安全问题 5.7. MySQL访问权限系统 5.7.1. 权限系统的作用 5.7.2. 权限系统工作原理 5.7.3. MySQL提供的权限 5.7.4. 与MySQL服务器连接 5.7.5. 访问控制, 阶段1:连接核实 5.7.6. 访问控制, 阶段2:请求核实 5.7.7. 权限更改何时生效 5.7.8. 拒绝访问错误的原因 5.7.9. MySQL 4.1中的密码哈希处理 5.8. MySQL用户账户管理 5.8.1. MySQL用户名和密码 5.8.2. 向MySQL增加新用户账户 5.8.3. 从MySQL删除用户账户 5.8.4. 限制账户资源 5.8.5. 设置账户密码 5.8.6. 使你的密码安全 5.8.7. 使用安全连接 5.9. 备份与恢复 5.9.1. 数据库备份 5.9.2. 示例用备份与恢复策略 5.9.3. 自动恢复 5.9.4. 表维护和崩溃恢复 5.9.5. myisamchk:MyISAM表维护实用工具 5.9.6. 建立表维护计划 5.9.7. 获取关于表的信息 5.10. MySQL本地化和国际应用 5.10.1. 数据和排序用字符集 5.10.2. 设置错误消息语言 5.10.3. 添加新的字符集 5.10.4. 字符定义数组 5.10.5. 字符串比较支持 5.10.6. 多字节字符支持 5.10.7. 字符集问题 5.10.8. MySQL服务器时区支持 5.11. MySQL日志文件 5.11.1. 错误日志 5.11.2. 通用查询日志 5.11.3. 二进制日志 5.11.4. 慢速查询日志 5.11.5. 日志文件维护 5.12. 在同一台机器上运行多个MySQL服务器 5.12.1. 在Windows下运行多个服务器 5.12.2. 在Unix中运行多个服务器 5.12.3. 在多服务器环境中使用客户端程序 5.13. MySQL查询高速缓冲 5.13.1. 查询高速缓冲如何工作 5.13.2. 查询高速缓冲SELECT选项 5.13.3. 查询高速缓冲配置 5.13.4. 查询高速缓冲状态和维护 6. MySQL中的复制 6.1. 复制介绍 6.2. 复制实施概述 6.3. 复制实施细节 6.3.1. 复制主线程状态 6.3.2. 复制从I/O线程状态 6.3.3. 复制从SQL线程状态 6.3.4. 复制传递和状态文件 6.4. 如何设置复制 6.5. 不同MySQL版本之间的复制兼容性 6.6. 升级复制设置 6.6.1. 将复制升级到5.0版 6.7. 复制特性和已知问题 6.8. 复制启动选项 6.9. 复制FAQ 6.10. 复制故障诊断与排除 6.11. 通报复制缺陷 6.12. 多服务器复制中的Auto-Increment 7. 优化 7.1. 优化概述 7.1.1. MySQL设计局限与折衷 7.1.2. 为可移植性设计应用程序 7.1.3. 我们已将MySQL用在何处? 7.1.4. MySQL基准套件 7.1.5. 使用自己的基准 7.2. 优化SELECT语句和其它查询 7.2.1. EXPLAIN语法(获取SELECT相关信息) 7.2.2. 估计查询性能 7.2.3. SELECT查询的速度 7.2.4. MySQL怎样优化WHERE子句 7.2.5. 范围优化 7.2.6. 索引合并优化 7.2.7. MySQL如何优化IS NULL 7.2.8. MySQL如何优化DISTINCT 7.2.9. MySQL如何优化LEFT JOIN和RIGHT JOIN 7.2.10. MySQL如何优化嵌套Join 7.2.11. MySQL如何简化外部联合 7.2.12. MySQL如何优化ORDER BY 7.2.13. MySQL如何优化GROUP BY 7.2.14. MySQL如何优化LIMIT 7.2.15. 如何避免表扫描 7.2.16. INSERT语句的速度 7.2.17. UPDATE语句的速度 7.2.18. DELETE语句的速度 7.2.19. 其它优化技巧 7.3. 锁定事宜 7.3.1. 锁定方法 7.3.2. 表锁定事宜 7.4. 优化数据库结构 7.4.1. 设计选择 7.4.2. 使你的数据尽可能小 7.4.3. 列索引 7.4.4. 多列索引 7.4.5. MySQL如何使用索引 7.4.6. MyISAM键高速缓冲 7.4.7. MyISAM索引统计集合 7.4.8. MySQL如何计算打开的表 7.4.9. MySQL如何打开和关闭表 7.4.10. 在同一个数据库创建多个表的缺陷 7.5. 优化MySQL服务器 7.5.1. 系统因素和启动参数的调节 7.5.2. 调节服务器参数 7.5.3. 控制查询优化器的性能 7.5.4. 编译和链接怎样影响MySQL的速度 7.5.5. MySQL如何使用内存 7.5.6. MySQL如何使用DNS 7.6. 磁盘事宜 7.6.1. 使用符号链接 8. 客户端和实用工具程序 8.1. 客户端脚本和实用工具概述 8.2. myisampack:生成压缩、只读MyISAM表 8.3. mysqlMySQL命令行工具 8.3.1. 选项 8.3.2. mysql命令 8.3.3. 怎样从文本文件执行SQL语句 8.3.4. mysql技巧 8.4. mysqlaccess:用于检查访问权限的客户端 8.5. mysqladmin:用于管理MySQL服务器的客户端 8.6. mysqlbinlog:用于处理二进制日志文件的实用工具 8.7. mysqlcheck:表维护和维修程序 8.8. mysqldump:数据库备份程序 8.9. mysqlhotcopy:数据库备份程序 8.10. mysqlimport:数据导入程序 8.11. mysqlshow-显示数据库、表和列信息 8.12. myisamlog:显示MyISAM日志文件内容 8.13. perror:解释错误代码 8.14. replace:字符串替换实用工具 8.15. mysql_zap:杀死符合某一模式的进程 9. 语言结构 9.1. 文字 9.1.1. 字符串 9.1.2. 数 9.1.3. 十六进制 9.1.4. 布尔 9.1.5. 位字段 9.1.6. NULL 9.2. 数据库、表、索引、列和别名 9.2.1. 识别符限制条件 9.2.2. 识别符大小写敏感性 9.3. 用户变量 9.4. 系统变量 9.4.1. 结构式系统变量 9.5. 注释语法 9.6. MySQL中保留字的处理 10. 字符集支持 10.1. 常规字符集和校对 10.2. MySQL中的字符集和校对
目录 前言 1. 一般信息 1.1. 关于本手册 1.2. 本手册采用的惯例 1.3. MySQL AB概述 1.4. MySQL数据库管理系统概述 1.4.1. MySQL的历史 1.4.2. MySQL的的主要特性 1.4.3. MySQL稳定性 1.4.4. MySQL表最大能达到多少 1.4.5. 2000年兼容性 1.5. MaxDB数据库管理系统概述 1.5.1. 什么是MaxDB? 1.5.2. MaxDB的历史 1.5.3. MaxDB的特性 1.5.4. 许可和支持 1.5.5. MaxDB和MySQL之间的特性差异 1.5.6. MaxDB和MySQL之间的协同性 1.5.7. 与MaxDB有关的链接 1.6. MySQL发展大事记 1.6.1. MySQL 5.1的新特性 1.7. MySQL信息源 1.7.1. MySQL邮件列表 1.7.2. IRC(在线聊天系统)上的MySQL社区支持 1.7.3. MySQL论坛上的MySQL社区支持 1.8. MySQL标准的兼容性 1.8.1. MySQL遵从的标准是什么 1.8.2. 选择SQL模式 1.8.3. 在ANSI模式下运行MySQL 1.8.4. MySQL对标准SQL的扩展 1.8.5. MySQL与标准SQL的差别 1.8.6. MySQL处理约束的方式 2. 安装MySQL 2.1. 一般安装问题 2.1.1. MySQL支持的操作系统 2.1.2. 选择要安装的MySQL分发版 2.1.3. 怎样获得MySQL 2.1.4. 通过MD5校验和或GnuPG验证软件包的完整性 2.1.5. 安装布局 2.2. 使用二进制分发版的标准MySQL安装 2.3. 在Windows上安装MySQL 2.3.1. Windows系统要求 2.3.2. 选择安装软件包 2.3.3. 用自动安装器安装MySQL 2.3.4. 使用MySQL安装向导 2.3.5. 使用配置向导 2.3.6. 通过非安装Zip文件安装MySQL 2.3.7. 提取安装档案文件 2.3.8. 创建选项文件 2.3.9. 选择MySQL服务器类型 2.3.10. 首次启动服务器 2.3.11. 从Windows命令行启动MySQL 2.3.12. 以Windows服务方式启动MySQL 2.3.13. 测试MySQL安装 2.3.14. 在Windows环境下对MySQL安装的故障诊断与排除 2.3.15. 在Windows下升级MySQL 2.3.16. Windows版MySQL同Unix版MySQL对比 2.4. 在Linux下安装MySQL 2.5.在Mac OS X中安装MySQL 2.6. 在NetWare中安装MySQL 2.7. 在其它类Unix系统中安装MySQL 2.8. 使用源码分发版安装MySQL 2.8.1. 源码安装概述 2.8.2. 典型配置选项 2.8.3. 从开发源码树安装 2.8.4. 处理MySQL编译问题 2.8.5. MIT-pthreads注意事项 2.8.6. 在Windows下从源码安装MySQL 2.8.7. 在Windows下编译MySQL客户端 2.9. 安装后的设置和测试 2.9.1. Windows下安装后的过程 2.9.2. Unix下安装后的过程 2.9.3. 使初始MySQL账户安全 2.10. 升级MySQL 2.10.1. 从5.0版升级 2.10.2. 升级授权表 2.10.3. 将MySQL数据库拷贝到另一台机器 2.11. 降级MySQL 2.12. 具体操作系统相关的注意事项 2.12.1. Linux注意事项 2.12.2. Mac OS X注意事项 2.12.3. Solaris注意事项 2.12.4. BSD注意事项 2.12.5. 其它Unix注意事项 2.12.6. OS/2注意事项 2.13. Perl安装注意事项 2.13.1. 在Unix中安装Perl 2.13.2. 在Windows下安装ActiveState Perl 2.13.3. 使用Perl DBI/DBD接口的问题 3. 教程 3.1. 连接与断开服务器 3.2. 输入查询 3.3. 创建并使用数据库 3.3.1. 创建并选择数据库 3.3.2. 创建表 3.3.3. 将数据装入表中 3.3.4. 从表检索信息 3.4. 获得数据库和表的信息 3.5. 在批处理模式下使用mysql 3.6. 常用查询的例子 3.6.1. 列的最大 3.6.2. 拥有某个列的最大的行 3.6.3. 列的最大:按组 3.6.4. 拥有某个字段的组间最大的行 3.6.5. 使用用户变量 3.6.6. 使用外键 3.6.7. 根据两个键搜索 3.6.8. 根据天计算访问量 3.6.9. 使用AUTO_INCREMENT 3.7. 孪生项目的查询 3.7.1. 查找所有未分发的孪生项 3.7.2. 显示孪生对状态的表 3.8. 与Apache一起使用MySQL 4. MySQL程序概述 4.1. MySQL程序概述 4.2. 调用MySQL程序 4.3. 指定程序选项 4.3.1. 在命令行上使用选项 4.3.2. 使用选项文件 4.3.3. 用环境变量指定选项 4.3.4. 使用选项设置程序变量 5. 数据库管理 5.1. MySQL服务器和服务器启动脚本 5.1.1. 服务器端脚本和实用工具概述 5.1.2. mysqld-max扩展MySQL服务器 5.1.3. mysqld_safe:MySQL服务器启动脚本 5.1.4. mysql.server:MySQL服务器启动脚本 5.1.5. mysqld_multi:管理多个MySQL服务器的程序 5.2. mysqlmanager:MySQL实例管理器 5.2.1. 用MySQL实例管理器启动MySQL服务器 5.2.2. 连接到MySQL实例管理器并创建用户账户 5.2.3. MySQL实例管理器命令行选项 5.2.4. MySQL实例管理器配置文件 5.2.5. MySQL实例管理器识别的命令 5.3. mysqld:MySQL服务器 5.3.1. mysqld命令行选项 5.3.2. SQL服务器模式 5.3.3. 服务器系统变量 5.3.4. 服务器状态变量 5.4. mysql_fix_privilege_tables:升级MySQL系统表 5.5. MySQL服务器关机进程 5.6. 一般安全问题 5.6.1. 通用安全指南 5.6.2. 使MySQL在攻击者面前保持安全 5.6.3. Mysqld安全相关启动选项 5.6.4. LOAD DATA LOCAL安全问题 5.7. MySQL访问权限系统 5.7.1. 权限系统的作用 5.7.2. 权限系统工作原理 5.7.3. MySQL提供的权限 5.7.4. 与MySQL服务器连接 5.7.5. 访问控制, 阶段1:连接核实 5.7.6. 访问控制, 阶段2:请求核实 5.7.7. 权限更改何时生效 5.7.8. 拒绝访问错误的原因 5.7.9. MySQL 4.1中的密码哈希处理 5.8. MySQL用户账户管理 5.8.1. MySQL用户名和密码 5.8.2. 向MySQL增加新用户账户 5.8.3. 从MySQL删除用户账户 5.8.4. 限制账户资源 5.8.5. 设置账户密码 5.8.6. 使你的密码安全 5.8.7. 使用安全连接 5.9. 备份与恢复 5.9.1. 数据库备份 5.9.2. 示例用备份与恢复策略 5.9.3. 自动恢复 5.9.4. 表维护和崩溃恢复 5.9.5. myisamchk:MyISAM表维护实用工具 5.9.6. 建立表维护计划 5.9.7. 获取关于表的信息 5.10. MySQL本地化和国际应用 5.10.1. 数据和排序用字符集 5.10.2. 设置错误消息语言 5.10.3. 添加新的字符集 5.10.4. 字符定义数组 5.10.5. 字符串比较支持 5.10.6. 多字节字符支持 5.10.7. 字符集问题 5.10.8. MySQL服务器时区支持 5.11. MySQL日志文件 5.11.1. 错误日志 5.11.2. 通用查询日志 5.11.3. 二进制日志 5.11.4. 慢速查询日志 5.11.5. 日志文件维护 5.12. 在同一台机器上运行多个MySQL服务器 5.12.1. 在Windows下运行多个服务器 5.12.2. 在Unix中运行多个服务器 5.12.3. 在多服务器环境中使用客户端程序 5.13. MySQL查询高速缓冲 5.13.1. 查询高速缓冲如何工作 5.13.2. 查询高速缓冲SELECT选项 5.13.3. 查询高速缓冲配置 5.13.4. 查询高速缓冲状态和维护 6. MySQL中的复制 6.1. 复制介绍 6.2. 复制实施概述 6.3. 复制实施细节 6.3.1. 复制主线程状态 6.3.2. 复制从I/O线程状态 6.3.3. 复制从SQL线程状态 6.3.4. 复制传递和状态文件 6.4. 如何设置复制 6.5. 不同MySQL版本之间的复制兼容性 6.6. 升级复制设置 6.6.1. 将复制升级到5.0版 6.7. 复制特性和已知问题 6.8. 复制启动选项 6.9. 复制FAQ 6.10. 复制故障诊断与排除 6.11. 通报复制缺陷 6.12. 多服务器复制中的Auto-Increment 7. 优化 7.1. 优化概述 7.1.1. MySQL设计局限与折衷 7.1.2. 为可移植性设计应用程序 7.1.3. 我们已将MySQL用在何处? 7.1.4. MySQL基准套件 7.1.5. 使用自己的基准 7.2. 优化SELECT语句和其它查询 7.2.1. EXPLAIN语法(获取SELECT相关信息) 7.2.2. 估计查询性能 7.2.3. SELECT查询的速度 7.2.4. MySQL怎样优化WHERE子句 7.2.5. 范围优化 7.2.6. 索引合并优化 7.2.7. MySQL如何优化IS NULL 7.2.8. MySQL如何优化DISTINCT 7.2.9. MySQL如何优化LEFT JOIN和RIGHT JOIN 7.2.10. MySQL如何优化嵌套Join 7.2.11. MySQL如何简化外部联合 7.2.12. MySQL如何优化ORDER BY 7.2.13. MySQL如何优化GROUP BY 7.2.14. MySQL如何优化LIMIT 7.2.15. 如何避免表扫描 7.2.16. INSERT语句的速度 7.2.17. UPDATE语句的速度 7.2.18. DELETE语句的速度 7.2.19. 其它优化技巧 7.3. 锁定事宜 7.3.1. 锁定方法 7.3.2. 表锁定事宜 7.4. 优化数据库结构 7.4.1. 设计选择 7.4.2. 使你的数据尽可能小 7.4.3. 列索引 7.4.4. 多列索引 7.4.5. MySQL如何使用索引 7.4.6. MyISAM键高速缓冲 7.4.7. MyISAM索引统计集合 7.4.8. MySQL如何计算打开的表 7.4.9. MySQL如何打开和关闭表 7.4.10. 在同一个数据库创建多个表的缺陷 7.5. 优化MySQL服务器 7.5.1. 系统因素和启动参数的调节 7.5.2. 调节服务器参数 7.5.3. 控制查询优化器的性能 7.5.4. 编译和链接怎样影响MySQL的速度 7.5.5. MySQL如何使用内存 7.5.6. MySQL如何使用DNS 7.6. 磁盘事宜 7.6.1. 使用符号链接 8. 客户端和实用工具程序 8.1. 客户端脚本和实用工具概述 8.2. myisampack:生成压缩、只读MyISAM表 8.3. mysqlMySQL命令行工具 8.3.1. 选项 8.3.2. mysql命令 8.3.3. 怎样从文本文件执行SQL语句 8.3.4. mysql技巧 8.4. mysqlaccess:用于检查访问权限的客户端 8.5. mysqladmin:用于管理MySQL服务器的客户端 8.6. mysqlbinlog:用于处理二进制日志文件的实用工具 8.7. mysqlcheck:表维护和维修程序 8.8. mysqldump:数据库备份程序 8.9. mysqlhotcopy:数据库备份程序 8.10. mysqlimport:数据导入程序 8.11. mysqlshow-显示数据库、表和列信息 8.12. myisamlog:显示MyISAM日志文件内容 8.13. perror:解释错误代码 8.14. replace:字符串替换实用工具 8.15. mysql_zap:杀死符合某一模式的进程 9. 语言结构 9.1. 文字 9.1.1. 字符串 9.1.2. 数 9.1.3. 十六进制 9.1.4. 布尔 9.1.5. 位字段 9.1.6. NULL 9.2. 数据库、表、索引、列和别名 9.2.1. 识别符限制条件 9.2.2. 识别符大小写敏感性 9.3. 用户变量 9.4. 系统变量 9.4.1. 结构式系统变量 9.5. 注释语法 9.6. MySQL中保留字的处理 10. 字符集支持 10.1. 常规字符集和校对 10.2. MySQL中的字符集和校对 10.3. 确定默认字符集和校对 10.3.1. 服务器字符集和校对 10.3.2. 数据库字符集和校对 10.3.3. 表字符集和校对 10.3.4. 列字符集和校对 10.3.5. 字符集和校对分配示例 10.3.6. 连接字符集和校对 10.3.7. 字符串文字字符集和校对 10.3.8. 在SQL语句中使用COLLATE 10.3.9. COLLATE子句优先 10.3.10. BINARY操作符 10.3.11. 校对确定较为复杂的一些特殊情况 10.3.12. 校对必须适合字符集 10.3.13. 校对效果的示例 10.4. 字符集支持影响到的操作 10.4.1. 结果字符串 10.4.2. CONVERT() 10.4.3. CAST() 10.4.4. SHOW语句 10.5. Unicode支持 10.6. 用于元数据的UTF8 10.7. 与其它DBMS的兼容性 10.8. 新字符集配置文件格式 10.9. 国家特有字符集 10.10. MySQL支持的字符集和校对 10.10.1. Unicode字符集 10.10.2. 西欧字符集 10.10.3. 中欧字符集 10.10.4. 南欧与中东字符集 10.10.5. 波罗的海字符集 10.10.6. 西里尔字符集 10.10.7. 亚洲字符集 11. 列类型 11.1. 列类型概述 11.1.1. 数类型概述 11.1.2. 日期和时间类型概述 11.1.3. 字符串类型概述 11.2. 数类型 11.3. 日期和时间类型 11.3.1. DATETIME、DATE和TIMESTAMP类型 11.3.2. TIME类型 11.3.3. YEAR类型 11.3.4. Y2K事宜和日期类型 11.4. String类型 11.4.1. CHAR和VARCHAR类型 11.4.2. BINARY和VARBINARY类型 11.4.3. BLOB和TEXT类型 11.4.4. ENUM类型 11.4.5. SET类型 11.5. 列类型存储需求 11.6. 选择正确的列类型 11.7. 使用来自其他数据库引擎的列类型 12. 函数和操作符 12.1. 操作符 12.1.1. 操作符优先级 12.1.2. 圆括号 12.1.3. 比较函数和操作符 12.1.4. 逻辑操作符 12.2. 控制流程函数 12.3. 字符串函数 12.3.1. 字符串比较函数 12.4. 数函数 12.4.1. 算术操作符 12.4.2. 数学函数 12.5. 日期和时间函数 12.6. MySQL使用什么日历? 12.7. 全文搜索功能 12.7.1. 布尔全文搜索 12.7.2. 全文搜索带查询扩展 12.7.3. 全文停止字 12.7.4. 全文限定条件 12.7.5. 微调MySQL全文搜索 12.8. Cast函数和操作符 12.9. 其他函数 12.9.1. 位函数 12.9.2. 加密函数 12.9.3. 信息函数 12.9.4. 其他函数 12.10. 与GROUP BY子句同时使用的函数和修改程序 12.10.1. GROUP BY(聚合)函数 12.10.2. GROUP BY修改程序 12.10.3. 具有隐含字段的GROUP BY 13. SQL语句语法 13.1. 数据定义语句 13.1.1. ALTER DATABASE语法 13.1.2. ALTER TABLE语法 13.1.3. CREATE DATABASE语法 13.1.4. CREATE INDEX语法 13.1.5. CREATE TABLE语法 13.1.6. DROP DATABASE语法 13.1.7. DROP INDEX语法 13.1.8. DROP TABLE语法 13.1.9. RENAME TABLE语法 13.2. 数据操作语句 13.2.1. DELETE语法 13.2.2. DO语法 13.2.3. HANDLER语法 13.2.4. INSERT语法 13.2.5. LOAD DATA INFILE语法 13.2.6. REPLACE语法 13.2.7. SELECT语法 13.2.8. Subquery语法 13.2.9. TRUNCATE语法 13.2.10. UPDATE语法 13.3. MySQL实用工具语句 13.3.1. DESCRIBE语法(获取有关列的信息) 13.3.2. USE语法 13.4. MySQL事务处理和锁定语句 13.4.1. START TRANSACTION, COMMIT和ROLLBACK语法 13.4.2. 不能回滚的语句 13.4.3. 会造成隐式提交的语句 13.4.4. SAVEPOINT和ROLLBACK TO SAVEPOINT语法 13.4.5. LOCK TABLES和UNLOCK TABLES语法 13.4.6. SET TRANSACTION语法 13.4.7. XA事务 13.5. 数据库管理语句 13.5.1. 账户管理语句 13.5.2. 表维护语句 13.5.3. SET语法 13.5.4. SHOW语法 13.5.5. 其它管理语句 13.6. 复制语句 13.6.1. 用于控制主服务器的SQL语句 13.6.2. 用于控制从服务器的SQL语句 13.7. 用于预处理语句的SQL语法 14. 插件式存储引擎体系结构 14.1. 前言 14.2. 概述 14.3. 公共MySQL数据库服务器层 14.4. 选择存储引擎 14.5. 将存储引擎指定给表 14.6. 存储引擎和事务 14.7. 插入存储引擎 14.8. 拔出存储引擎 14.9. 插件式存储器的安全含义 15. 存储引擎和表类型 15.1. MyISAM存储引擎 15.1.1. MyISAM启动选项 15.1.2. 键所需的空间 15.1.3. MyISAM表的存储格式 15.1.4. MyISAM表方面的问题 15.2. InnoDB存储引擎 15.2.1. InnoDB概述 15.2.2. InnoDB联系信息 15.2.3. InnoDB配置 15.2.4. InnoDB启动选项 15.2.5. 创建InnoDB表空间 15.2.6. 创建InnoDB表 15.2.7. 添加和删除InnoDB数据和日志文件 15.2.8. InnoDB数据库的备份和恢复 15.2.9. 将InnoDB数据库移到另一台机器上 15.2.10. InnoDB事务模型和锁定 15.2.11. InnoDB性能调节提示 15.2.12. 多版本的实施 15.2.13. 表和索引结构 15.2.14. 文件空间管理和磁盘I/O 15.2.15. InnoDB错误处理 15.2.16. 对InnoDB表的限制 15.2.17. InnoDB故障诊断与排除 15.3. MERGE存储引擎 15.3.1. MERGE表方面的问题 15.4. MEMORY (HEAP)存储引擎 15.5. BDB (BerkeleyDB)存储引擎 15.5.1. BDB支持的操作系统 15.5.2. 安装BDB 15.5.3. BDB启动选项 15.5.4. BDB表的特性 15.5.5. 修改BDB所需的事宜 15.5.6. 对BDB表的限制 15.5.7. 使用BDB表时可能出现的错误 15.6. EXAMPLE存储引擎 15.7. FEDERATED存储引擎 15.7.1. 安装FEDERATED存储引擎 15.7.2. FEDERATED存储引擎介绍 15.7.3. 如何使用FEDERATED表 15.7.4. FEDERATED存储引擎的局限性 15.8. ARCHIVE存储引擎 15.9. CSV存储引擎 15.10. BLACKHOLE存储引擎 16. 编写自定义存储引擎 16.1. 前言 16.2. 概述 16.3. 创建存储引擎源文件 16.4. 创建handlerton 16.5. 对处理程序进行实例化处理 16.6. 定义表扩展 16.7. 创建表 16.8. 打开表 16.9. 实施基本的表扫描功能 16.9.1. 实施store_lock()函数 16.9.2. 实施external_lock()函数 16.9.3. 实施rnd_init()函数 16.9.4. 实施info()函数 16.9.5. 实施extra()函数 16.9.6. 实施rnd_next()函数 16.10. 关闭表 16.11. 为存储引擎添加对INSERT的支持 16.12. 为存储引擎添加对UPDATE的支持 16.13. 为存储引擎添加对DELETE的支持 16.14. API引用 16.14.1. bas_ext 16.14.2. close 16.14.3. create 16.14.4. delete_row 16.14.5. delete_table 16.14.6. external_lock 16.14.7. extra 16.14.8. info 16.14.9. open 16.14.10. rnd_init 16.14.11. rnd_next 16.14.12. store_lock 16.14.13. update_row 16.14.14. write_row 17. MySQL簇 17.1. MySQL簇概述 17.2. MySQL簇的基本概念 17.3. 多计算机的简单基础知识 17.3.1. 硬件、软件和联网 17.3.2. 安装 17.3.3. 配置 17.3.4. 首次启动 17.3.5. 加载示例数据并执行查询 17.3.6. 安全关闭和重启 17.4. MySQL簇的配置 17.4.1. 从源码创建MySQL簇 17.4.2. 安装软件 17.4.3. MySQL簇的快速测试设置 17.4.4. 配置文件 17.5. MySQL簇中的进程管理 17.5.1. 用于MySQL簇的MySQL服务器进程使用 17.5.2. ndbd,存储引擎节点进程 17.5.3. ndb_mgmd,“管理服务器”进程 17.5.4. ndb_mgm,“管理客户端”进程 17.5.5. 用于MySQL簇进程的命令选项 17.6. MySQL簇的管理 17.6.1. MySQL簇的启动阶段 17.6.2. “管理客户端”中的命令 17.6.3. MySQL簇中生成的事件报告 17.6.4. 单用户模式 17.6.5. MySQL簇的联机备份 17.7. 使用与MySQL簇的高速互连 17.7.1. 配置MySQL簇以使用SCI套接字 17.7.2. 理解簇互连的影响 17.8. MySQL簇的已知限制 17.9. MySQL簇发展的重要历程 17.9.1. MySQL 5.0中的MySQL簇变化 17.9.2. 关于MySQL簇的MySQL 5.1发展历程 17.10. MySQL簇常见问题解答 17.11. MySQL簇术语表 18. 分区 18.1. MySQL中的分区概述 18.2. 分区类型 18.2.1. RANGE分区 18.2.2. LIST分区 18.2.3. HASH分区 18.2.4. KEY分区 18.2.5. 子分区 18.2.6. MySQL分区处理NULL的方式 18.3. 分区管理 18.3.1. RANGE和LIST分区的管理 18.3.2. HASH和KEY分区的管理 18.3.3. 分区维护 18.3.4. 获取关于分区的信息 19. MySQL中的空间扩展 19.1. 前言 19.2. OpenGIS几何模型 19.2.1. Geometry类的层次 19.2.2. 类Geometry 19.2.3. 类Point 19.2.4. 类Curve 19.2.5. 类LineString 19.2.6. 类Surface 19.2.7. 类Polygon 19.2.8. 类GeometryCollection 19.2.9. 类MultiPoint 19.2.10. 类MultiCurve 19.2.11. 类MultiLineString 19.2.12. 类MultiSurface 19.2.13. 类MultiPolygon 19.3. 支持的空间数据格式 19.3.1. 著名的文本(WKT)格式 19.3.2. 著名的二进制(WKB)格式 19.4. 创建具备空间功能的MySQL数据库 19.4.1. MySQL空间数据类型 19.4.2. 创建空间 19.4.3. 创建空间列 19.4.4. 填充空间列 19.4.5. 获取空间数据 19.5. 分析空间信息 19.5.1. Geometry格式转换函数 19.5.2. Geometry函数 19.5.3. 从已有Geometry创建新Geometry的函数 19.5.4. 测试几何对象间空间关系的函数 19.5.5. 关于几何最小边界矩形(MBR)的关系 19.5.6. 测试几何类之间空间关系的函数 19.6. 优化空间分析 19.6.1. 创建空间索引 19.6.2. 使用空间索引 19.7. MySQL的一致性和兼容性 19.7.1. 尚未实施的GIS特性 20. 存储程序和函数 20.1. 存储程序和授权表 20.2. 存储程序的语法 20.2.1. CREATE PROCEDURE和CREATE FUNCTION 20.2.2. ALTER PROCEDURE和ALTER FUNCTION 20.2.3. DROP PROCEDURE和DROP FUNCTION 20.2.4. SHOW CREATE PROCEDURE和SHOW CREATE FUNCTION 20.2.5. SHOW PROCEDURE STATUS和SHOW FUNCTION STATUS 20.2.6. CALL语句 20.2.7. BEGIN ... END复合语句 20.2.8. DECLARE语句 20.2.9. 存储程序中的变量 20.2.10. 条件和处理程序 20.2.11. 光标 20.2.12. 流程控制构造 20.3. 存储程序、函数、触发程序和复制:常见问题 20.4. 存储子程序和触发程序的二进制日志功能 21. 触发程序 21.1. CREATE TRIGGER语法 21.2. DROP TRIGGER语法 21.3. 使用触发程序 22. 视图 22.1. ALTER VIEW语法 22.2. CREATE VIEW语法 22.3. DROP VIEW语法 22.4. SHOW CREATE VIEW语法 23. INFORMATION_SCHEMA信息数据库 23.1. INFORMATION_SCHEMA表 23.1.1. INFORMATION_SCHEMA SCHEMATA表 23.1.2. INFORMATION_SCHEMA TABLES表 23.1.3. INFORMATION_SCHEMA COLUMNS表 23.1.4. INFORMATION_SCHEMA STATISTICS表 23.1.5. INFORMATION_SCHEMA USER_PRIVILEGES表 23.1.6. INFORMATION_SCHEMA SCHEMA_PRIVILEGES表 23.1.7. INFORMATION_SCHEMA TABLE_PRIVILEGES表 23.1.8. INFORMATION_SCHEMA COLUMN_PRIVILEGES表 23.1.9. INFORMATION_SCHEMA CHARACTER_SETS表 23.1.10. INFORMATION_SCHEMA COLLATIONS表 23.1.11. INFORMATION_SCHEMA COLLATION_CHARACTER_SET_APPLICABILITY表 23.1.12. INFORMATION_SCHEMA TABLE_CONSTRAINTS表 23.1.13. INFORMATION_SCHEMA KEY_COLUMN_USAGE表 23.1.14. INFORMATION_SCHEMA ROUTINES表 23.1.15. INFORMATION_SCHEMA VIEWS表 23.1.16. INFORMATION_SCHEMA TRIGGERS表 23.1.17. 其他INFORMATION_SCHEMA表 23.2. SHOW语句的扩展 24. 精度数学 24.1. 数的类型 24.2. DECIMAL数据类型更改 24.3. 表达式处理 24.4. 四舍五入 24.5. 精度数学示例 25. API和库 25.1. libmysqld,嵌入式MySQL服务器库 25.1.1. 嵌入式MySQL服务器库概述 25.1.2. 使用libmysqld编译程序 25.1.3. 使用嵌入式MySQL服务器时的限制 25.1.4. 与嵌入式服务器一起使用的选项 25.1.5. 嵌入式服务器中尚需完成的事项(TODO) 25.1.6. 嵌入式服务器示例 25.1.7. 嵌入式服务器的许可 25.2. MySQL C API 25.2.1. C API数据类型 25.2.2. C API函数概述 25.2.3. C API函数描述 25.2.4. C API预处理语句 25.2.5. C API预处理语句的数据类型 25.2.6. C API预处理语句函数概述 25.2.7. C API预处理语句函数描述 25.2.8. C API预处理语句方面的问题 25.2.9. 多查询执行的C API处理 25.2.10. 日期和时间的C API处理 25.2.11. C API线程函数介绍 25.2.12. C API嵌入式服务器函数介绍 25.2.13. 使用C API时的常见问题 25.2.14. 创建客户端程序 25.2.15. 如何生成线程式客户端 25.3. MySQL PHP API 25.3.1. 使用MySQL和PHP的常见问题 25.4. MySQL Perl API 25.5. MySQL C++ API 25.5.1. Borland C++ 25.6. MySQL Python API 25.7. MySQL Tcl API 25.8. MySQL Eiffel Wrapper 25.9. MySQL程序开发实用工具 25.9.1. msql2mysql:转换mSQL程序以用于MySQL 25.9.2. mysql_config:获取编译客户端的编译选项 26. 连接器 26.1. MySQL Connector/ODBC 26.1.1. MyODBC介绍 26.1.2. 关于ODBC和MyODBC的一般信息 26.1.3. 如何安装MyODBC 26.1.4. 在Windows平台上从二进制版本安装MyODBC 26.1.5. I在Unix平台上从二进制版本安装MyODBC 26.1.6. 在Windows平台上从源码版本安装MyODBC 26.1.7. 在Unix平台上从源码版本安装MyODBC 26.1.8. 从BitKeeper开发源码树安装MyODBC 26.1.9. MyODBC配置 26.1.10. 与MyODBC连接相关的事宜 26.1.11. MyODBC和Microsoft Access 26.1.12. MyODBC和Microsoft VBA及ASP 26.1.13. MyODBC和第三方ODBC工具 26.1.14. MyODBC通用功能 26.1.15. 基本的MyODBC应用步骤 26.1.16. MyODBC API引用 26.1.17. MyODBC数据类型 26.1.18. MyODBC错误代码 26.1.19. MyODBC与VB:ADO、DAO和RDO 26.1.20. MyODBC与Microsoft.NET 26.1.21. 感谢 26.2. MySQL Connector/NET 26.2.1. 前言 26.2.2. 下载并安装MySQL Connector/NET 26.2.3. Connector/NET体系结构 26.2.4. 使用MySQL Connector/NET 26.2.5. MySQL Connector/NET变更史 26.3. MySQL Connector/J 26.3.1. 基本的JDBC概念 26.3.2. 安装 Connector/J 26.3.3. JDBC引用 26.3.4. 与J2EE和其他Java框架一起使用 Connector/J 26.3.5. 诊断 Connector/J方面的问题 26.3.6. Changelog 26.4. MySQL Connector/MXJ 26.4.1. 前言 26.4.2. 支持平台: 26.4.3. Junit测试要求 26.4.4. 运行Junit测试 26.4.5. 作为JDBC驱动程序的一部分运行 26.4.6. 在Java对象中运行 26.4.7. MysqldResource API 26.4.8. 在JMX代理(custom)中运行 26.4.9. 部署在标准的JMX代理环境下 (JBoss) 26.4.10. 安装 27. 扩展MySQL 27.1. MySQL内部控件 27.1.1. MySQL线程 27.1.2. MySQL测试套件 27.2. 为MySQL添加新函数 27.2.1. 自定义函数接口的特性 27.2.2. CREATE FUNCTION/DROP FUNCTION语法 27.2.3. 添加新的自定义函数 27.2.4. 添加新的固有函数 27.3. 为MySQL添加新步骤 27.3.1. 步骤分析 27.3.2. 编写步骤 A. 问题和常见错误 A.1. 如何确定导致问题的原因 A.2. 使用MySQL程序时的常见错误 A.2.1. 拒绝访问 A.2.2. 无法连接到[local] MySQL服务器 A.2.3. 客户端不支持鉴定协议 A.2.4. 输入密码时出现密码错误 A.2.5. 主机的host_name被屏蔽 A.2.6. 连接数过多 A.2.7. 内存溢出 A.2.8. MySQL服务器不可用 A.2.9. 信息包过大 A.2.10. 通信错误和失效连接 A.2.11. 表已满 A.2.12. 无法创建文件/写入文件 A.2.13. 命令不同步 A.2.14. 忽略用户 A.2.15. 表tbl_name不存在 A.2.16. 无法初始化字符集 A.2.17. 文件未找到 A.3. 与安装有关的事宜 A.3.1. 与MySQL客户端库的链接问题 A.3.2. 如何以普通用户身份运行MySQL A.3.3. 与文件许可有关的问题 A.4. 与管理有关的事宜 A.4.1. 如何复位根用户密码 A.4.2. 如果MySQL依然崩溃,应作些什么 A.4.3. MySQL处理磁盘满的方式 A.4.4. MySQL将临时文件储存在哪里 A.4.5. 如何保护或更改MySQL套接字文件/tmp/mysql.sock A.4.6. 时区问题 A.5. 与查询有关的事宜 A.5.1. 搜索中的大小写敏感性 A.5.2. 使用DATE列方面的问题 A.5.3. 与NULL有关的问题 A.5.4. 与列别名有关的问题 A.5.5. 非事务表回滚失败 A.5.6. 从相关表删除行 A.5.7. 解决与不匹配行有关的问题 A.5.8. 与浮点比较有关的问题 A.6. 与优化器有关的事宜 A.7. 与表定义有关的事宜 A.7.1. 与ALTER TABLE有关的问题 A.7.2. 如何更改表中的列顺序 A.7.3. TEMPORARY TABLE问题 A.8. MySQL中的已知事宜 A.8.1. MySQL中的打开事宜 B. 错误代码和消息 B.1. 服务器错误代码和消息 B.2. 客户端错误代码和消息 C. 感谢 C.1. MySQL AB处的开发人 C.2. MySQL贡献人 C.3. 资料员和译员 C.4. MySQL使用和包含的库 C.5. 支持MySQL的软件包 C.6. 用于创建MySQL的工具 C.7. MySQL支持人员 D. MySQL变更史 D.1. 5.1.x版中的变更情况(开发) D.1.1. 5.1.2版中的变更情况(尚未发布) D.1.2. 5.1.1版中的变更情况(尚未发布) D.2. MyODBC的变更情况 D.2.1. MyODBC 3.51.12的变更情况 D.2.2. MyODBC 3.51.11的变更情况 E. 移植到其他系统 E.1. 调试MySQL服务器 E.1.1. 针对调试编译MySQL E.1.2. 创建跟踪文件 E.1.3. 在gdb环境下调试mysqld E.1.4. 使用堆栈跟踪 E.1.5. 使用日志文件找出mysqld中的错误原因 E.1.6. 如果出现表崩溃,请生成测试案例 E.2. 调试MySQL客户端 E.3. DBUG软件包 E.4. 关于RTS线程的注释 E.5. 线程软件包之间的差异 F. 环境变量 G. MySQL正则表达式 H. MySQL中的限制 H.1. 联合的限制 I. 特性限制 I.1. 对存储子程序和触发程序的限制 I.2. 对服务器端光标的限制 I.3. 对子查询的限制 I.4. 对视图的限制 I.5. 对XA事务的限制 J. GNU通用公共许可 K. MySQL FLOSS许可例外 索引 图形清单 14.1. MySQL插件式存储引擎的体系结构 14.2. 存储引擎比较 16.1. MySQL体系结构

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值