目录
本章通过演示如何使用mysql客户程序创造和使用一个简单的数据库,提供一?span>MySQL的入门教程?b>mysql(有时称为“终端监视器”或只是“监视”)是一个交互式程序,允许你连接一?span>MySQL服务器,运行查询并察看结果?b>mysql可以用于批模式:你预先把查询放在一个文件中,然后告?b>mysql执行文件的内容。本章将介绍使用mysql的两个方法?/p>
要想查看?b>mysql提供的选择项目表,可以?span>--help选项来调用:
shell> mysql --help
本章假定mysql已经被安装在你的机器上,并且有一?span>MySQL服务器可以连接。否则,请联?span>MySQL管理员。(如果?/i>是管理员,则需要查阅本手册的其它章节,例如?章:数据库管?/i>。)
本章描述建立和使用一个数据库的全过程。如果你仅仅对访问一个已经存在的数据库感兴趣,可以跳过描述怎样创建数据库及它所包含的表的章节?/p>
由于本章是一个教程,省略了许多细节。关于这里所涉及的主题的详细信息,请查阅本手册的相关章节?/p>
Enter password: ********
host?span>user分别代表MySQL服务器运行的主机名和MySQL账户用户名。设置时替换为正确的值?span>******** 代表你的密码;当mysql显示Enter password:提示时输入它?/p>
如果有效,你应该看见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准备为你输入命令?/p>
一?strong>MySQL安装允许用户以匿名(未命名)用户连接到本地主机上运行的服务器。如果你的机器是这种情况,你应该能不带任何选项地调?span>mysql与该服务器连接:
shell> mysql
成功地连接后,可以在mysql>提示下输?span>QUIT (?span>\q)随时退出:
mysql> QUIT
Bye
?span>Unix中,也可以按control-D键断开服务器?/p>
在下列章节的大多数例子都假设你连接到了服务器。由mysql>提示指明?/p>
确保你连接上了服务器,如在先前的章节讨论的。连接上服务器并布代表选择了任何数据库,但这样就可以了。知道关于如何查询的基本知识,比马上跳至创建表、给他们装载数据并且从他们检索数据更重要。本节描述输入命令的基本原则,使用几个查询,你能尝试了解mysql是如何工作的?/p>
这是一个简单的命令,要求服务器告诉它的版本号和当前日期。在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>
这询问说?b>mysql的几个方?span>:
· 一个命令通常?span>SQL语句组成,随后跟着一个分号。(有一些例外不需要分号。早先提到的QUIT是一个例子。后面我们将看到其它的例子。)
· 当发出一个命令时?b>mysql将它发送给服务器并显示执行结果,然后显示另一?span>mysql>显示它准备好接受其它命令?/p>
· mysql用表?span>(行和?span>)方式显示查询输出。第一行包含列的标签,随后的行是查询结果。通常,列标签是你取自数据库表的列的名字。如果你正在检索一个表达式而非表列的?span>(如刚才的例子)?b>mysql用表达式本身标记列?/p>
· mysql显示返回了多少行,以及查询花了多长时间,它给你提供服务器性能的一个大致概念。因为他们表示时钟时?span>(不是 CPU 或机器时?span>),并且因为他们受到诸如服务器负载和网络延时的影响,因此这些值是不精确的。(为了简洁,在本章其它例子中不再显示“集合中的行”。)
能够以大小写输入关键词。下列查询是等价的:
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)
不必全在一个行内给出一个命令,较长命令可以输入到多个行中?b>mysql通过寻找终止分号而不是输入行的结束来决定语句在哪儿结束。(换句话说?b>mysql接受自由格式的输入:它收集输入行但直到看见分号才执行。)
这里是一个简单的多行语句的例子:
mysql> SELECT
-> USER()
-> ,
-> CURRENT_DATE;
+---------------+--------------+
| USER() | CURRENT_DATE |
+---------------+--------------+
| jon@localhost | 2005-10-11 |
+---------------+--------------+
在这个例子中,在输入多行查询的第一行后,要注意提示符如何从mysql>变为->,这正是mysql如何指出它没见到完整的语句并且正在等待剩余的部分。提示符是你的朋友,因为它提供有价值的反馈,如果使用该反馈,将总是知道mysql正在等待什么?/p>
如果你决定不想执行正在输入过程中的一个命令,输入\c取消它:
mysql> SELECT
-> USER()
-> \c
mysql>
这里也要注意提示符,在你输入\c以后,它切换回到mysql>,提供反馈以表明mysql准备接受一个新命令?/p>
下表显示出可以看见的各个提示符并简述它们所表示?b>mysql的状态:
|
提示?/span> |
含义 |
|
mysql> |
准备好接受新命令?/td> |
|
-> |
等待多行命令的下一行?/td> |
|
'> |
等待下一行,等待以单引号(?span>'?span>)开始的字符串的结束?/td> |
|
"> |
等待下一行,等待以双引号(?span>"?span>)开始的字符串的结束?/td> |
|
`> |
等待下一行,等待以反斜点(?span>`?span>)开始的识别符的结束?/td> |
|
/*> |
等待下一行,等待?span>/*开始的注释的结束?/td> |
当你打算在一个单行上发出一个命令时,通常会“偶然”出现多行语句,但是没有终止分号。在这种情况中,mysql等待进一步输入:
mysql> SELECT USER()
->
如果出现这种情况(你认为输完了语句,但是只有一?span>->提示符响?span>),很可能mysql正在等待分号。如果你没有注意到提示符的提示,在意识到你需要做什么之前,你可能会呆坐一会儿。输入一个分号完成语句,mysql将执行:
mysql> SELECT USER()
-> ;
+---------------+
| USER() |
+---------------+
| jon@localhost |
+---------------+
在字符串收集期间将出? '> ?span> "> 提示符(提示MySQL正等待字符串的结束)。在MySQL中,可以写由?span>'’或?span>"’字符括起来的字符串 (例如?span>'hello'?span>"goodbye"),并?b>mysql允许输入跨越多行的字符串。当看到一? '> ? "> 提示符时,这意味着已经输入了包含以?span>'’或?span>"’括号字符开始的字符串的一行,但是还没有输入终止字符串的匹配引号。这显示你粗心地省掉了一个引号字符。例如:
mysql> SELECT * FROM my_table WHERE name = 'Smith AND age < 30;
'>
如果你输?span>SELECT语句,然后按Enter?/span>回车?/b>键并等待结果,什么都没有出现。不要惊讶,“为什么该查询这么长呢?”,注意">提示符提供的线索。它告诉?span>mysql期望见到一个未终止字符串的余下部分。(你看见语句中的错误吗?字符串"Smith丢掉了第二个引号。)
走到这一步,你该做什么?最简单的是取消命令。然而,在这种情况下,你不能只是输入\c,因?b>mysql作为它正在收集的字符串的一部分来解释它!相反,应输入关闭的引号字符(这样mysql知道你完成了字符?span>),然后输?span>\c?/p>
mysql> SELECT * FROM my_table WHERE name = 'Smith AND age < 30;
'> '\c
mysql>
提示符回?span>mysql>,显?b>mysql准备好接受一个新命令了?/p>
`> 提示符类似于 '> ?span>"> 提示符,但表示你已经开始但没有结束?span>`> 开始的识别符?/p>
知道'>?span>">提示符的含义很重要,因为如果你错误地输入一个未终止的字符串,任何后面输入的行将要被mysql忽略--包括包含QUIT的行!这可能令人相当困惑,特别是如果取消当前命令前还不知道你需要提供终止引号?/div>
知道怎样输入命令,便可以访问数据库了?/p>
假定在你的家(你的“动物园?span>)中有很多宠物,并且你想跟踪关于它们各种类型的信息。你可以通过创建表来保存你的数据并根据所需要的信息装载他们,然后你可以从表中检索数据来回答关于动物不同种类的问题。本节显示如何做到所有这些事情:
· 创建数据?/p>
· 创建数据库表
· 装载数据到数据库?/p>
· 以各种方法从表中检索数?/p>
· 使用多个?/p>
动物园数据库很简?span>(特意?span>),但是不难把它想象成可能用到类似数据库的真实世界情况。例如,农夫可以使用这样的一个数据库来追踪家畜,或者兽医可以用它跟踪病畜记录。从MySQL网址上可以获得后面章节中将用到的含有部分查询和样例数据的动物园分发。有tar压缩格式 (http://www.mysql.com/Downloads/Contrib/Examples/menagerie.tar.gz)?span>Zip压缩格式 (http://www.mysql.com/Downloads/Contrib/Examples/menagerie.zip)?/p>
使用SHOW语句找出服务器上当前存在什么数据库?/p>
mysql> SHOW DATABASES;
+----------+
| Database |
+----------+
| mysql |
| test |
| tmp |
+----------+
可能你的机器上的数据库列表是不同的,但是很可能有mysql?span>test数据库?span>mysql是必需的,因为它描述用户访问权限,test数据库经常作为用户试身手的工作区?/p>
请注意如果没?span>SHOW DATABASES权限,则不能看见所有数据库。参?a href="sql-syntax.html#grant" title="13.5.1.3. GRANT and REVOKE Syntax">13.5.1.3节,“GRANT和REVOKE语法?/a>?/p>
如果test数据库存在,尝试访问它:
mysql> USE test
Database changed
注意?span>USE,类?span>QUIT,不需要一个分号。(如果你喜欢,你可以用一个分号终止这样的语句;这无碍?span>USE语句在使用上也有另外一个特殊的地方:它必须在一个单行上给出?/p>
你可列在后面的例子中使用test数据?span>(如果你能访问?span>),但是你在该数据库创建的任何东西可以被访问它的其它人删除,因此,你应该询?span>MySQL管理员许可你使用自己的一个数据库。假定你想要调用你的menagerie,管理员需要执行这样一条命令:
mysql> GRANT ALL ON menagerie.* TO 'your_mysql_name'@'your_client_host';
这里your_mysql_name是分配给你的MySQL用户名,your_client_host是所连接的服务器所在的主机?/p>
?span>Unix下,数据库名称是区分大小写的(不像SQL关键?span>),因此你必须总是?span>menagerie访问数据库,而不能用Menagerie?span>MENAGERIE或其它一些变量。对表名也是这样的。(?span>Windows下,该限制不适用,尽管你必须在一个给定的查询中使用同样的大小写来引用数据库和表。但是,由于多种原因,作为最好的惯例,一定要使用与数据库创建时的同样的大小写。)
创建数据库并不表示选定并使用它,你必须明确地操作。为了使menagerie成为当前的数据库,使用这个命令:
mysql> USE menagerie
Database changed
数据库只需要创建一次,但是必须在每次启?b>mysql会话时在使用前先选择它。你可以根据上面的例子执行一?span>USE语句来实现。还可以在调?b>mysql时,通过命令行选择数据库,只需要在提供连接参数之后指定数据库名称。例如:
shell> mysql -h host -u user -p menagerie
Enter password: ********
注意,刚才显示的命令行中?span>menagerie?/b>是你? 密码。如果你想要在命令行上在-p选项后提? 密码,则不能插入空格(例如,如-pmypassword,不?span>-p
mypassword)。但是,不建议在命令行输入密码,因为这样会暴? 密码,能被在机器上登录的其它用户窥探到?/p>
3.3.2. 创建?/h3>
创建数据库是很容易的部分,但是在这时它是空的,正?span>SHOW TABLES将告诉你的:
mysql> SHOW TABLES;
Empty set (0.00 sec)
较难的部分是决定你的数据库结构应该是什么:你需要什么数据库表,各数据库表中有什么样的列?/p>
你将需要一个包含你每个宠物的记录的表。它可称?span>pet表,并且它应该包含,最少,每个动物的名字。因为名字本身不是很有趣,表应该包含另外的信息。例如,如果在你豢养宠物的家庭有超过一个人,你可能想要列出每个动物的主人。你可能也想要记录例如种类和性别的一些基本的描述信息?/span>
年龄呢?那可能有趣,但是存储到一个数据库中不是一件好事情。年龄随着时间流逝而变化,这意味着你将要不断地更新你的记录。相?span>, 存储一个固定值例如生日比较好,那么,无论何时你需要年龄,可以以当前日期和出生日期之间的差来计算它?strong>MySQL提供了日期运算函数,因此这并不困难。存储出生日期而非年龄还有其它优点?/p>
· 你可以使用数据库完成这样的任务,例如生成即将到来的宠物生日的提示。(如果你认为这类查询有点蠢,注意,这与从商务数据库来识别出不久要发给生日祝贺的客户是同一个问题,因为计算机帮助私人联络。)
· 你可以相对于日期而不止是当前日期来计算年龄。例如,如果你在数据库存储死亡日期,你能很容易地计算出一只宠物死时有多大?/p>
你可能想?span>pet表中其它有用的其它类型信息,但是到目前为止这些已经足够了:名字、主人、种类,性别、出生和死亡日期?/p>
使用一?span>CREATE TABLE语句指定你的数据库表的布局?/p>
mysql> CREATE TABLE pet (name VARCHAR(20), owner VARCHAR(20),
-> species VARCHAR(20), sex CHAR(1), birth DATE, death DATE);
VARCHAR适合?span>name?span>owner?span>species列,因为列值是变长的。这些列的长度不必都相同,而且不必?span>20。你可以挑选从1?span>65535的任何长度,从中选择一个最合理的值。(如果选择得不合适,后来证明你需要一个更长的字段?strong>MySQL提供一?span>ALTER TABLE语句。)
可以用多种类型的值来表示动物记录中的性别,例如,"m"?span>"f",或"male"?span>"female"。使用单字符"m"?span>"f"是最简单的方法?/p>
很显然,birth?span>death列应选用DATE数据类?/p>
创建了数据库表后?span>SHOW TABLES应该产生一些输出:
mysql> SHOW TABLES;
+---------------------+
| Tables in menagerie |
+---------------------+
| pet |
+---------------------+
为了验证你的表是按你期望的方式创建,使用一?span>DESCRIBE语句?/p>
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 | |
+---------+-------------+------+-----+---------+-------+
你可以随时使?span>DESCRIBE,例如,如果你忘记表中的列的名称或类型时?/div>
创建表后,需要填入内容。通过LOAD DATA?span>INSERT语句可以完成该任务?/p>
假定你的宠物纪录描述如下。(假定?strong>MySQL中期望的日期格式?span>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 |
|
因为你是从一个空表开始的,填充它的一个简易方法是创建一个文本文件,每个动物各一行,然后用一个语句将文件的内容装载到表中?/p>
你可以创建一个文本文?tt>?/span>pet.txt?/span>,每行包含一个记录,用定位符(tab)把值分开,并且以CREATE
TABLE语句中列出的列次序给出。对于丢失的?span>(例如未知的性别,或仍然活着的动物的死亡日期),你可以使用NULL值。为了在你的文本文件中表示这些内容,使用\N(反斜线,字?span>N?/span>。例如,Whistler鸟的记录应为(这里值之间的空白是一个定位符)?/p>
name
owner
species
sex
birth
death
Whistler
Gwen
bird
\N
1997-12-09
\N 要想将文本文?/span>?/span>pet.txt?/span>装载?/span>pet表中,使用这个命令: 请注意如果用Windows中的编辑器(使用\r\n做为行的结束?span>?/span>创建文件,应使用?/p>
(在运行OS X?span>Apple
mysql> LOAD DATA LOCAL INFILE '/path/pet.txt' INTO TABLE pet;
mysql> LOAD DATA LOCAL INFILE '/path/pet.txt' INTO TABLE pet
-> LINES TERMINATED BY '\r\n';
如果你愿意,你能明确地在LOAD
DATA语句中指出列值的分隔符和行尾标记,但是默认标记是定位符和换行符。这对读入文?tt>?/span>pet.txt?/span>的语句已经足够?/p>
如果该语句失败,可能是你安装?span>MySQL 如果想要一次增加一个新记录,可以使?span>INSERT?/a>?/p>
mysql> INSERT INTO pet
-> VALUES ('Puffball','Diane','hamster','f','1999-03-30',NULL);
注意,这里字符串和日期值均为引号扩起来的字符串。另外,可以直接?span>INSERT语句插入NULL代表不存在的值。不能使?span>LOAD DATA中所示的?span>\N?/p>
从这个例子,你应该能看到涉及很多的键入用多个INSERT语句而非单个LOAD DATA语句装载你的初始记录?/div>
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?/span>例如,刚刚装载了初始数据集以后。也有可能你想到Bowser的生日看起来不很对。查阅你原来的家谱,你发现正确的出生年是1989,而不?span>1979?/p>
至少有两种修正方法:
· 编辑文件?/span>pet.txt?/span>改正错误,然后使?span>DELETE?span>LOAD DATA清空并重新装载表:
· mysql> DELETE FROM pet;
· mysql> LOAD DATA LOCAL INFILE 'pet.txt' INTO TABLE pet;
然?span>, 如果这样操做,必须重新输?span>Puffball记录?/p>
· 用一?span>UPDATE语句仅修正错误记录:
· mysql> UPDATE pet SET birth = '1989-08-31' WHERE name = 'Bowser';
UPDATE只更改有问题的记录,不需要重新装载数据库表?/p>
mysql> SELECT * FROM pet WHERE name = 'Bowser';
+--------+-------+---------+------+------------+------------+
| name | owner | species | sex | birth | death |
+--------+-------+---------+------+------------+------------+
| Bowser | Diane | dog | m | 1989-08-31 | 1995-07-29 |
+--------+-------+---------+------+------------+------------+
输出证实正确的年份记录为1989,而不?span>1979?/p>
字符串比较时通常对大小些不敏感,因此你可以将名字指定?span>"bowser"?span>"BOWSER"等,查询结果相同?/p>
你可以在任何列上指定条件,不只仅仅是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 |
+-------+--------+---------+------+------------+-------+
上面的查询使?span>AND逻辑操作符,也有一?span>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?span>OR可以混用,但AND?span>OR具有更高的优先级。如果你使用两个操作符,使用圆括号指明如何对条件进行分组是一个好主意?/p>
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 |
+-------+--------+---------+------+------------+-------+
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 |
+----------+------------+
找出谁拥有宠物,使用这个查询?/p>
mysql> SELECT owner FROM pet;
+--------+
| owner |
+--------+
| Harold |
| Gwen |
| Harold |
| Benny |
| Diane |
| Gwen |
| Gwen |
| Benny |
| Diane |
+--------+
请注意该查询只是简单地检索每个记录的owner列,并且他们中的一些出现多次。为了使输出减到最少,增加关键?span>DISTINCT检索出每个唯一的输出记录:
mysql> SELECT DISTINCT owner FROM pet;
+--------+
| owner |
+--------+
| Benny |
| Diane |
| Gwen |
| Harold |
+--------+
可以使用一?span>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 |
+--------+---------+------------+
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强制执行区分大小写的分类功能,如?span>ORDER BY BINARY col_name.
默认排序是升序,最小的值在第一。要想以降序排序,在你正在排序的列名上增?span>DESC(降? )关键字?/p>
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 |
+----------+------------+
可以对多个列进行排序,并且可以按不同的方向对不同的列进行排序。例如,按升序对动物的种类进行排序,然后按降序根据生日对各动物种类进行排序(最年轻的动物在最前面),使用下列查询?/p>
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列的排序顺序?/p>
MySQL提供了几个函数,可以用来计算日期,例如,计算年龄或提取日期部分?/p>
要想确定每个宠物有多大,可以计算当前日期的年和出生日期之间的差。如果当前日期的日历年比出生日期早,则减去一年。以下查询显示了每个宠物的出生日期、当前日期和年龄数值的年数字?/p>
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 |
+----------+------------+------------+------+
此处?span>YEAR()提取日期的年部分?span>RIGHT()提取日期?span>MM-DD (日历?span>)部分的最右面5个字符。比?span>MM-DD值的表达式部分的值一般为1?span>0,如?span>CURDATE()的年?span>birth的年早,则年份应减去1。整个表达式有些难懂,使?em>alias (age)来使输出的列标记更有意义?/p>
尽管查询可行,如果以某个顺序排列行,则能更容易地浏览结果。添?span>ORDER BY name子句按照名字对输出进行排序则能够实现?/p>
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 |
+----------+------------+------------+------+
为了?span>age而非name排序输出,只要再使用一?span>ORDER BY子句?/p>
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 |
+----------+------------+------------+------+
可以使用一个类似的查询来确定已经死亡动物的死亡年龄。你通过检?span>death值是否是NULL来确定是哪些动物,然后,对于那些?span>NULL值的动物,需要计算出death?span>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,因?span>NULL是特殊的值,不能使用普通比较符来比较,以后会给出解释。参?a href="tutorial.html#working-with-null" title="3.3.4.6. Working with NULL Values">3.3.4.6节,“NULL值操?code class="literal">?/a>?/p>
如果你想要知道哪个动物下个月过生日,怎么办?对于这类计算,年和天是无关的,你只需要提?span>birth列的月份部分?strong>MySQL提供几个日期部分的提取函数,例如YEAR( )?span>MONTH( )?span>DAYOFMONTH( )。在这里MONTH()是适合的函数。为了看它怎样工作,运行一个简单的查询,显?span>birth?span>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 |
+----------+------------+--------------+
找出下个月生日的动物也是容易的。假定当前月?span>4月,那么月值是4?/span>你可以找?span>5月出生的动物 (5?span>),方法是?/p>
mysql> SELECT name, birth FROM pet WHERE MONTH(birth) = 5;
+-------+------------+
| name | birth |
+-------+------------+
| Buffy | 1989-05-13 |
+-------+------------+
如果当前月份?span>12月,就有点复杂了。你不能只把1加到月份?span>(12)上并寻找?span>13月出生的动物,因为没有这样的月份。相反,你应寻找?span>1月出生的动物(1?span>) ?/p>
你甚至可以编写查询,不管当前月份是什么它都能工作。采用这种方法不必在查询中使用一个特定的月份?span>DATE_ADD( )允许在一个给定的日期上加上时间间隔。如果在NOW( )值上加上一个月,然后用MONTH()提取月份,结果产生生日所在月份:
mysql> SELECT name, birth FROM pet
-> WHERE MONTH(birth) = MONTH(DATE_ADD(CURDATE(),INTERVAL 1 MONTH));
完成该任务的另一个方法是?span>1以得出当前月份的下一个月(在使用取模函?span>(MOD)后,如果月份当前值是12,则“回滚”到?span>0)?/p>
mysql> SELECT name, birth FROM pet
-> WHERE MONTH(birth) = MOD(MONTH(CURDATE()), 12) + 1;
注意?span>MONTH返回?span>1?span>12之间的一个数字,?span>MOD(something,12)返回?span>0?span>11之间的一个数字,因此必须?span>MOD( )以后?span>1,否则我们将?span>11?span>( 11 )跳到1?span>(1)?/div>
NULL值可能令人感到奇怪直到你习惯它。概念上?span>NULL意味着“没有值”或“未知值”,且它被看作与众不同的值。为了测?span>NULL,你不能使用算术比较 操作符例?span>=?span><?span>!=。为了说明它,试试下列查询:
mysql> SELECT 1 = NULL, 1 <> NULL, 1 < NULL, 1 > NULL;
+----------+-----------+----------+----------+
| 1 = NULL | 1 <> NULL | 1 < NULL | 1 > NULL |
+----------+-----------+----------+----------+
| NULL | NULL | NULL | NULL |
+----------+-----------+----------+----------+
很显然你不能通过这些比较得到有意义的结果。相反使?span>IS NULL?span>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?/span>
?span>NULL的特殊处理即是在前面的章节中,为了决定哪个动物不再是活着的,使用death IS NOT NULL而不使用death != NULL的原因?/p>
?span>GROUP BY中,两个NULL值视为相同?/p>
执行ORDER BY时,如果运行 ORDER BY ... ASC?/span>?span>NULL值出现在最前面,若运行ORDER BY ... DESC,则NULL值出现在最后面?/p>
NULL操作的常见错误是不能在定义为NOT NULL的列内插?span>0或空字符串,但事实并非如此。在NULL表示"没有数?span>"的地方有数值。使?span>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的列内插?span>0或空字符串,实际?span>NOT
NULL。参?a href="problems.html#problems-with-null" title="A.5.3. Problems with NULL Values">A.5.3节,“与NULL值有关的问题?/a>?/div>
MySQL提供标准?span>SQL模式匹配,以及一种基于象Unix实用程序?span>vi?/b>grep?span>sed的扩展正则表达式模式匹配的格式?/p>
SQL模式匹配允许你使?samp>?/span>_?/span>匹配任何单个字符,?samp>?/span>%?/span>匹配任意数目字符(包括零字?span>)。在 MySQL中,SQL的模式默认是忽略大小写的。下面给出一些例子。注意使?span>SQL模式时,不能使用=?span>!=;而应使用LIKE?span>NOT LIKE比较操作符?/p>
要想找出?samp>?/span>b?/span>开头的名字?/p>
要想找出?samp>?/span>fy?/span>结尾的名字: 要想找出包含?/span>w?/span>的名字: 要想找出正好包含5个字符的名字,使?samp>?/span>_?/span>模式字符?/p>
?strong>MySQL提供的模式匹配的其它类型是使用扩展正则表达式。当你对这类模式进行匹配测试时,使用REGEXP?span>NOT
REGEXPmysql> 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 |
+--------+--------+---------+------+------------+------------+
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 |
+--------+--------+---------+------+------------+-------+
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 |
+----------+-------+---------+------+------------+------------+
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 |
+-------+--------+---------+------+------------+-------+
扩展正则表达式的一些字符是?
· ?span>.’匹配任何单个的字符?/p>
·
字符?samp>?/span>[...]?/span>匹配在方括号内的任何字符。例如,?/span>[abc]?/span>匹配?/span>a?/span>?samp>?/span>b?/span>?samp>?/span>c?/span>。为了命名字符的范围,使用一个?span>-”?samp>?/span>[a-z]?/span>匹配任何字母,?samp>?/span>[0-9]?/span>匹配任何数字?/p>
·
?/span>
* ?/span>匹配零个或多个在它前面的字符。例如,?/span>x*?/span>匹配任何数量?samp>?/span>x?/span>字符?samp>?/span>[0-9]*?/span>匹配任何数量的数字,?samp>?/span>.*?/span>匹配任何数量的任何字符?/p>
为了说明扩展正则表达式如何工作,下面使用REGEXP重写上面所示的LIKE查询?/p>
为了找出?samp>?/span>b?/span>开头的名字,使?samp>?/span>^?/span>匹配名字的开始: 如果你想强制?span>REGEXP 为了找出?samp>?/span>fy?/span>结尾的名字,使用?/span>$?/span>匹配名字的结尾: 为了找出包含一?samp>?/span>w?/span>的名字,使用以下查询?/p>
既然如果一个正则表达式出现在值的任何地方,其模式匹配了,就不必在先前的查询中在模式的两侧放置一个通配符以使得它匹配整个值,就像你使用了一?span>SQL 为了找出包含正好5个字符的名字,使?samp>?/span>^?/span>?samp>?/span>$?/span>匹配名字的开始和结尾,和5?samp>?/span>.?/span>实例在两者之间: 你也可以使用?/span>{n}?/span>“重?span>n 附录G?/a>MySQL正则表达?/i>
提供了关于正则表达式的句法的详细信息?/div> 在前面,你检索了拥有宠物的人的名字。如果你想要知道每个主人有多少宠物,你可以使?span>COUNT(
)函数?/span> 注意,使?span>GROUP
BY对每?span>owner的所有记录分组,没有它,你会得到错误消息?/p>
COUNT( )?span>GROUP
BY以各种方式分类你的数据。下列例子显示出进行动物普查操作的不同方式?/p>
每种动物的数量: 每种性别的动物数量: (在这个输出中,NULL表示“未知性别”。) 按种类和性别组合的动物数量: 若使?span>COUNT( ),你不必检索整个表。例?span>,
前面的查询,当只对狗和猫进行时,应为?/p>
或,如果你仅需要知道已知性别的按性别的动物数目:
?
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 |
+--------+--------+---------+------+------------+------------+
mysql> SELECT * FROM pet WHERE name REGEXP BINARY '^b';
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 |
+--------+--------+---------+------+------------+-------+
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 |
+----------+-------+---------+------+------------+------------+
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 |
+-------+--------+---------+------+------------+-------+
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 |
+-------+--------+---------+------+------------+-------+
mysql> SELECT COUNT(*) FROM pet;
+----------+
| COUNT(*) |
+----------+
| 9 |
+----------+
mysql> SELECT owner, COUNT(*) FROM pet GROUP BY owner;
+--------+----------+
| owner | COUNT(*) |
+--------+----------+
| Benny | 2 |
| Diane | 2 |
| Gwen | 3 |
| Harold | 2 |
+--------+----------+
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
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 |
+------+----------+
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 |
+---------+------+----------+
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个以上的?br>
· 它需要包含宠物名字以便你知道每个事件属于哪个动物?/p>
· 需要一个日期以便你知道事件是什么时候发生的?/p>
· 需要一个描述事件的字段?/p>
· 如果你想要对事件进行分类,则需要一个事件类型字段?/p>
综合上述因素?span>event表的CREATE TABLE语句应为?/p>
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 |
采用如下方式装载记录?/p>
mysql> LOAD DATA LOCAL INFILE 'event.txt' INTO TABLE event;
根据你从已经运行?span>pet表上的查询中学到的,你应该能执行?span>event表中记录的检索;原理是一样的。但是什么时?span>event表本身不能回答你可能问的问题呢?
当他们有了一窝小动物时,假定你想要找出每只宠物的年龄。我们前面看到了如何通过两个日期计算年龄?span>event表中有母亲的生产日期,但是为了计算母亲的年龄,你需要她的出生日期,存储?span>pet表中。说明查询需要两个表?/p>
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 |
+--------+------+-----------------------------+
关于该查询要注意的几件事情:
你不必有2个不同的表来进行联结。如果你想要将一个表的记录与同一个表的其它记录进行比较,可以将一个表联结到自身。例如,为了在你的宠物之中繁殖配偶,你可以用pet联结自身来进行相似种类的雄雌配对?/span>
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 |
+--------+------+--------+------+---------+
在这个查询中,我们为表名指定别名以便能引用列并且使得每一个列引用与哪个表实例相关联更直观?/p>
mysql> SELECT DATABASE();
+------------+
| DATABASE() |
+------------+
| menagerie |
+------------+
如果你还没选择任何数据库,结果?span>NULL?/p>
为了找出当前的数据库包含什么表(例如,当你不能确定一个表的名?span>),使用这个命令:
mysql> SHOW TABLES;
+---------------------+
| Tables in menagerie |
+---------------------+
| event |
| pet |
+---------------------+
如果你想要知道一个表的结构,可以使用DESCRIBE命令;它显示表中每个列的信息?/p>
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显示列是否被索引?span>Default指定列的默认值?/p>
如果表有索引?span>SHOW INDEX FROM tbl_name生成有关索引的信息?/p>
shell> mysql < batch-file
如果?span>Windows下运?strong>mysql,并且文件中有一些可以造成问题的特殊字符,可以这样操作?/p>
C:\> mysql -e "source batch-file"
如果你需要在命令行上指定连接参数,命令应为:
shell> mysql -h host -u user -p < batch-file
Enter password: ********
当这样操?span>mysql时,则创建一个脚本文件,然后执行脚本?/p>
如果你想在语句出现错误的时候仍想继续执行脚本,则应使用--force命令行选项?/p>
为什么要使用一个脚本?有很多原因:
· shell> mysql < batch-file | more
· shell> mysql < batch-file > mysql.out
当你以批模式运行mysql时,比起你交互地使用它时,其默认输出格式是不同的(更简明些)。例如,当交互式运行SELECT DISTINCT species FROM pet时,输出应为?/p>
+---------+
| species |
+---------+
| bird |
| cat |
| dog |
| hamster |
| snake |
+---------+
但是当以批模式运行时,输出应为:
species
bird
cat
dog
hamster
snake
如果你想要在批模式中得到交互输出格式,使?span>mysql -t。为了回显以输出被执行的命令,使?span>mysql -vvv?/p>
你还可以使用源代码或 \.命令?strong>mysql提示符运行脚本:
mysql> source filename;
mysql> \. filename
下面是一些学习如何用MySQL解决一些常见问题的例子?/p>
在一些例子中,使用数据库表?span>shop”来储存某个商人(经销商)的每件物?span>(物品?span>)的价格。假定每个商人对每项物品有一个固定价格,那么(物品,商?span>)即为该记录的主关键字?/p>
启动命令行工?strong>mysql并选择数据库:
shell> mysql your-database-name
(在大多?span>MySQL中,你可以使?span>test数据库)?/p>
你可以使用以下语句创建示例表?/p>
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);
执行语句后,表应包含以下内容?/p>
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 |
+---------+--------+-------+
“最大的物品号是什么??/p>
SELECT MAX(article) AS article FROM shop; +---------+ | article | +---------+ | 4 | +---------+
这很容易用一个子查询做到?/p>
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;
?/span>:如果有多项最贵的物品( 例如每个的价格为19.95)?span>LIMIT解决方案仅仅显示其中一个!
任务:每项物品的的最高价格是多少?/span>
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 | +---------+-------+
任务:对每项物品,找出最贵价格的物品的经销商?/span>
可以用这样一个子查询解决该问题:
SELECT article, dealer, price
FROM shop s1
WHERE price=(SELECT MAX(s2.price)
FROM shop s2
WHERE s1.article = s2.article);
你可以清?span>MySQL用户变量以记录结果,不必将它们保存到客户端的临时变量中。(参见
9.3节,“用户变量?/a>.)?/p>
例如,要找出价格最高或最低的物品的,其方法是?/p>
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 |
+---------+--------+-------+