一个命令不必全在一个单独行给出,所以需要多行的较长命令不是一个问题。mysql
通过寻找终止的分号而不是寻找输入行的结束来决定你的语句在哪儿结束。(换句话说,mysql
接受自由格式输入:它收集输入行但执行他们直到它看见分号。)
这里是一个简单的多行语句的例子:
mysql> SELECT -> USER() -> , -> CURRENT_DATE; +--------------------+--------------+ | USER() | CURRENT_DATE | +--------------------+--------------+ | joesmith@localhost | 1999-03-18 | +--------------------+--------------+
在这个例子中,在你输入一个多行查询的第一行后,要注意提示符如何从mysql>
变为->
,这正是mysql
如何指出它没见到完整的语句并且正在等待剩余的部分。提示符是你的朋友,因为它提供有价值的反馈,如果你使用该反馈,你将总是知道mysql
正在等待什么。
如果你决定,你不想要执行你在输入过程中输入的一个命令,打入\c
取消它:
mysql> SELECT -> USER() -> \c mysql>
这里也要注意提示符,在你打入\c
以后,它切换回到mysql>
,提供反馈以表明mysql
准备接受一个新命令。
下表显示出你可以看见的各个提示符并总结他们意味着mysql
在什么状态下:
提示符 | 意思 |
mysql> |
准备好接受新命令 |
-> |
等待多行命令的下一行 |
'> |
等待下一行,收集以单引号(“'”)开始的字符串 |
"> |
等待下一行,收集以双引号(“"”)开始的字符串 |
如果你忘记了MySQL的root
用户的口令,你可以用下列过程恢复它。
kill
(不是kill -9
)到mysqld
服务器来关闭mysqld服务器。pid 被保存在一个.pid
文件中,通常在MySQL数据库目录中: kill `cat /mysql-data-directory/hostname.pid`
你必须是一个UNIX root
用户或运行服务器的相同用户做这个。
--skip-grant-tables
选项重启mysqld
。 mysql -h hostname mysql
连接mysqld服务器并且用一条GRANT
命令改变口令。见7.26 GRANT
和REVOKE
句法。你也可以用mysqladmin -h hostname -u user password 'new password'
进行。 mysqladmin -h hostname flush-privileges
或用SQL命令FLUSH PRIVILEGES
来装载权限表。
DATE
列的问题一个DATE
值的格式是'YYYY-MM-DD'
。根据ANSI SQL,不允许其他格式。你应该在UPDATE
表达式和SELECT
语句的WHERE子句中使用这个格式。例如:
mysql> SELECT * FROM tbl_name WHERE date >= '1997-05-05';
为了方便,如果日期用在数字上下文,MySQL自动变换一个日期到一个数字(并且反过来也如此)。当更新时和将一个日期与TIMESTAMP
、DATE
或DATETIME
列比较的一个WHERE
子句中,也是足够灵活以允许一种“宽松”的字符串格式。(宽松格式意味着任何标点字符用作在部件之间的分割符。例如,'1998-08-15'
和'1998#08#15'
是等价的。)MySQL也能变换不包含分割符的一个字符串(例如 '19980815'
),如果它作为一个日期说得通。
特殊日期'0000-00-00'
可以作为'0000-00-00'
被存储和检索。
当通过MyODBC使用一个'0000-00-00'
日期时,在MyODBC 2.50.12和以上版本,它将自动被转换为NULL
,因为ODBC不能处理这种日期。
因为MySQL实行了上述的变换,下列语句可以工作:
mysql> INSERT INTO tbl_name (idate) VALUES (19970505); mysql> INSERT INTO tbl_name (idate) VALUES ('19970505'); mysql> INSERT INTO tbl_name (idate) VALUES ('97-05-05'); mysql> INSERT INTO tbl_name (idate) VALUES ('1997.05.05'); mysql> INSERT INTO tbl_name (idate) VALUES ('1997 05 05'); mysql> INSERT INTO tbl_name (idate) VALUES ('0000-00-00'); mysql> SELECT idate FROM tbl_name WHERE idate >= '1997-05-05'; mysql> SELECT idate FROM tbl_name WHERE idate >= 19970505; mysql> SELECT mod(idate,100) FROM tbl_name WHERE idate >= 19970505; mysql> SELECT idate FROM tbl_name WHERE idate >= '19970505';
然而,下列将不工作:
mysql> SELECT idate FROM tbl_name WHERE STRCMP(idate,'19970505')=0;
STRCMP()
是字符串函数,因此它将idate
转换为一个字符串并且实施字符串比较。它不将'19970505'
转换为一个日期并实施日期比较。
注意,MySQL不检查日期是否正确。如果你存储一个不正确的日期,例如'1998-2-31'
,错误的日期将被存储。如果日期不能被变换到任何合理的值,在DATE
字段中存储一个0
。这主要是一个速度问题并且我们认为检查日期是应用程序的责任,而不服务器。
确保你连接上了服务器,如在先前的章节讨论的。这样做本身将不选择任何数据库来工作,但是那很好。从这点讲,知道关于如何出询问的一点知识,比马上跳至创建表、给他们装载数据并且从他们检索数据要来的重要写。本节描述输入命令的基本原则,使用几个查询,你能尝试让自己mysql
是如何工作的。
这是一个简单的命令,要求服务器告诉你它的版本号和当前日期。在mysql>
提示打入如下命令并按回车键:
mysql> SELECT VERSION(), CURRENT_DATE; +--------------+--------------+ | version() | CURRENT_DATE | +--------------+--------------+ | 3.22.20a-log | 1999-03-19 | +--------------+--------------+ 1 row in set (0.01 sec) mysql>
这询问说明关于mysql
几件事:
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.707107 | 25 | +-------------+---------+
至今显示的命令是相当短的,单行语句。你甚至能在单行上输入多条语句,只是以一个分号结束每一条:
mysql> SELECT VERSION(); SELECT NOW(); +--------------+ | version() | +--------------+ | 3.22.20a-log | +--------------+ +---------------------+ | NOW() | +---------------------+ | 1999-03-19 00:15:33 | +---------------------+
一个命令不必全在一个单独行给出,所以需要多行的较长命令不是一个问题。mysql
通过寻找终止的分号而不是寻找输入行的结束来决定你的语句在哪儿结束。(换句话说,mysql
接受自由格式输入:它收集输入行但执行他们直到它看见分号。)
这里是一个简单的多行语句的例子:
mysql> SELECT -> USER() -> , -> CURRENT_DATE; +--------------------+--------------+ | USER() | CURRENT_DATE | +--------------------+--------------+ | joesmith@localhost | 1999-03-18 | +--------------------+--------------+
在这个例子中,在你输入一个多行查询的第一行后,要注意提示符如何从mysql>
变为->
,这正是mysql
如何指出它没见到完整的语句并且正在等待剩余的部分。提示符是你的朋友,因为它提供有价值的反馈,如果你使用该反馈,你将总是知道mysql
正在等待什么。
如果你决定,你不想要执行你在输入过程中输入的一个命令,打入\c
取消它:
mysql> SELECT -> USER() -> \c mysql>
这里也要注意提示符,在你打入\c
以后,它切换回到mysql>
,提供反馈以表明mysql
准备接受一个新命令。
下表显示出你可以看见的各个提示符并总结他们意味着mysql
在什么状态下:
提示符 | 意思 |
mysql> |
准备好接受新命令 |
-> |
等待多行命令的下一行 |
'> |
等待下一行,收集以单引号(“'”)开始的字符串 |
"> |
等待下一行,收集以双引号(“"”)开始的字符串 |
当你打算在一个单行上发出一个命令时,多行语句通常“偶然”出现,但是忘记终止的分号。在这种情况中,mysql
等待进一步输入:
mysql> SELECT USER() ->
如果这发生在你身上(你认为你输完了语句但是唯一的反应是一个->
提示符),很可能mysql
正在等待分号。如果你没有注意到提示符正在告诉你什么,在认识到你需要做什么之前,你可能花一会儿时间呆坐在那儿。进入一个分号完成语句,并且mysql
将执行它:
mysql> SELECT USER() -> ; +--------------------+ | USER() | +--------------------+ | joesmith@localhost | +--------------------+
'>
和">
提示符出现在在字符串收集期间。在MySQL中,你可以写由“'”或“"”字符括起来的字符串 (例如,'hello'
或"goodbye"
),并且mysql
让你进入跨越多行的字符串。当你看到一个'>
或">
提示符时,这意味着你已经输入了包含以“'”或“"”括号字符开始的字符串的一行,但是还没有输入终止字符串的匹配引号。如果你确实正在输入一个多行字符串,很好,但是果真如此吗?不尽然。更常见的,'>
和">
提示符显示你粗心地省掉了一个引号字符。例如:
mysql> SELECT * FROM my_table WHERE name = "Smith AND age < 30; ">
如果你输入该SELECT
语句,然后按回车键并等待结果,什么都没有出现。不要惊讶,“为什么该查询这么长呢?”,注意">
提示符提供的线索。它告诉你mysql
期望见到一个未终止字符串的余下部分。(你在语句中看见错误吗?字符串"Smith
正好丢失第二个引号。)
走到这一步,你该做什么?最简单的是取消命令。然而,在这种情况下,你不能只是打入\c
,因为mysql
作为它正在收集的字符串的一部分来解释它!相反,输入关闭的引号字符(这样mysql
知道你完成了字符串),然后打入\c
:
mysql> SELECT * FROM my_table WHERE name = "Smith AND age < 30; "> "\c mysql>
提示符回到mysql>
,显示mysql
准备好接受一个新命令了。
知道'>
和">
提示符意味着什么是很重要的,因为如果你错误地输入一个未终止的字符串,任何比你下一步输入的行好象将要被mysql
忽略--包括包含QUIT
的行!这可能相当含糊,特别是在你能取消当前命令前,如果你不知道你需要提出终止引号。
下面是一些学习如何用MySQL解决一些常见问题的例子。
一些例子使用数据库表“shop”,包含某个商人的每篇文章(物品号)的价格。假定每个商人的每篇文章有一个单独的固定价格,那么(物品,商人)是记录的主键。
你能这样创建例子数据库表:
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)); 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);
好了,例子数据是这样的:
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 | +---------+--------+-------+
“最大的物品号是什么?”
SELECT MAX(article) AS article FROM shop +---------+ | article | +---------+ | 4 | +---------+
“找出最贵的文章的编号、商人和价格”
在ANSI-SQL中这很容易用一个子查询做到:
SELECT article, dealer, price FROM shop WHERE price=(SELECT MAX(price) FROM shop)
在MySQL中(还没有子查询)就用2步做到:
SELECT
语句从表中得到最大值。 SELECT article, dealer, price FROM shop WHERE price=19.95
另一个解决方案是按价格降序排序所有行并用MySQL特定LIMIT
子句只得到的第一行:
SELECT article, dealer, price FROM shop ORDER BY price DESC LIMIT 1
注意:如果有多个最贵的文章( 例如每个19.95),LIMIT
解决方案仅仅显示他们之一!
“每篇文章的最高的价格是什么?”
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 | +---------+-------+
“对每篇文章,找出有最贵的价格的交易者。”
在ANSI SQL
中,我可以用这样一个子查询做到:
SELECT article, dealer, price FROM shop s1 WHERE price=(SELECT MAX(s2.price) FROM shop s2 WHERE s1.article = s2.article)
在MySQL中,最好是分几步做到:
这可以很容易用一个临时表做到:
CREATE TEMPORARY TABLE tmp ( article INT(4) UNSIGNED ZEROFILL DEFAULT '0000' NOT NULL, price DOUBLE(16,2) DEFAULT '0.00' NOT NULL); LOCK TABLES article read; INSERT INTO tmp SELECT article, MAX(price) FROM shop GROUP BY article; SELECT article, dealer, price FROM shop, tmp WHERE shop.article=tmp.articel AND shop.price=tmp.price; UNLOCK TABLES; DROP TABLE tmp;
如果你不使用一个TEMPORARY
表,你也必须锁定“tmp”表。
“它能一个单个查询做到吗?”
是的,但是只有使用我称之为“MAX-CONCAT诡计”的一个相当低效的诡计:
SELECT article, SUBSTRING( MAX( CONCAT(LPAD(price,6,'0'),dealer) ), 7) AS dealer, 0.00+LEFT( MAX( CONCAT(LPAD(price,6,'0'),dealer) ), 6) AS price FROM shop GROUP BY article; +---------+--------+-------+ | article | dealer | price | +---------+--------+-------+ | 0001 | B | 3.99 | | 0002 | A | 10.99 | | 0003 | C | 1.69 | | 0004 | D | 19.95 | +---------+--------+-------+
最后例子当然能通过在客户程序中分割连结的列使它更有效一点。
不需要外键联结2个表。
MySQL
唯一不做的事情是CHECK
以保证你使用的键确实在你正在引用表中存在,并且它不自动从有一个外键定义的表中删除行。如果你象平常那样使用你的键值,它将工作得很好!
CREATE TABLE persons ( id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, name CHAR(60) NOT NULL, PRIMARY KEY (id) ); CREATE TABLE shirts ( 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 persons, PRIMARY KEY (id) ); INSERT INTO persons VALUES (NULL, 'Antonio Paz'); INSERT INTO shirts VALUES (NULL, 'polo', 'blue', LAST_INSERT_ID()), (NULL, 'dress', 'white', LAST_INSERT_ID()), (NULL, 't-shirt', 'blue', LAST_INSERT_ID()); INSERT INTO persons VALUES (NULL, 'Lilliana Angelovska'); INSERT INTO shirts VALUES (NULL, 'dress', 'orange', LAST_INSERT_ID()), (NULL, 'polo', 'red', LAST_INSERT_ID()), (NULL, 'dress', 'blue', LAST_INSERT_ID()), (NULL, 't-shirt', 'white', LAST_INSERT_ID()); SELECT * FROM persons; +----+---------------------+ | id | name | +----+---------------------+ | 1 | Antonio Paz | | 2 | Lilliana Angelovska | +----+---------------------+ SELECT * FROM shirts; +----+---------+--------+-------+ | 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 persons p, shirts 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 | +----+-------+--------+-------+
既然你知道怎样输入命令,现在是存取一个数据库的时候了。
假定在你的家(你的“动物园”)中有很多宠物,并且你想追踪关于他们各种各样类型的信息。你可以通过创建表来保存你的数据并根据所需要的信息装载他们做到,然后你可以通过从表中检索数据来回答关于你的动物不同种类的问题。本节显示如何做到所有这些事情:
动物园数据库将会是简单的(故意的),但是不难把它想象成可能用到相似类型数据库的真实世界情况。例如,这样的一个数据库能被一个农夫用来追踪家畜,或由一个兽医追踪病畜记录。
使用SHOW
语句找出在服务器上当前存在什么数据库:
mysql> SHOW DATABASES; +----------+ | Database | +----------+ | mysql | | test | | tmp | +----------+
数据库列表可能在你的机器上是不同的,但是mysql
和test
数据库很可能的在其间。mysql
是必需的,因为它描述用户存取权限,test
数据库经常作为一个工作区提供给用户试试身手。
如果test
数据库存在,尝试存取它:
mysql> USE test Database changed
注意,USE
,类似QUIT
,不需要一个分号。(如果你喜欢,你可以用一个分号终止这样的语句;这无碍)USE
语句在使用上也有另外一个特殊的地方:它必须在一个单行上给出。
你可列在后面的例子中使用test
数据库(如果你能访问它),但是你在该数据库创建的任何东西可以被与访问它的其他人删除,为了这个原因,你可能应该询问你的MySQL管理员许可你自己使用的一个数据库。假定你想要调用你的menagerie
,管理员需要执行一个这样的命令:
mysql> GRANT ALL ON menagerie.* TO your_mysql_name;
这里your_mysql_name
是分配给你的MySQL用户名。
如果在设置你的权限时,管理员为你创建了数据库,你可以开始使用它。否则,你需要自己创建它:
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
)。然而,不建议把你的口令放在命令行上,因为这样做把它暴露出来,能被在你的机器上登录的其他用户窥探到。
创建数据库是容易的部分,但是在这时它是空的,正如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
到255
的任何长度,无论哪个对你来说好象最合理。(如果你做了较差的选择,以后会变得你需要一个更长的字段,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
,例如,如果你忘记在你表中的列的名字或他们是什么类型。
在你创建表后,你需要充实它。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 | 1998-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
。例如,对Whistler鸟的记录看起来像这样的(这里在值之间的空白是一个单个的定位字符):
Whistler |
Gwen |
bird |
\N |
1997-12-09 |
\N |
为了装载文本文件“pet.txt”到pet
表中,使用这个命令:
mysql> LOAD DATA LOCAL INFILE "pet.txt" INTO TABLE pet;
如果你愿意,你能明确地在LOAD DATA
语句中指出列值的分隔符和行尾标记,但是缺省是定位符和换行符。这些对争取读入文件“pet.txt”的语句是足够的。
当你想要一次增加一个新记录时,INSERT
语句是有用的。在它最简单的形式,你为每一列提供值,以列在CREATE TABLE
语句被列出的顺序。假定Diane把一只新仓鼠命名为Puffball,你可以使用一个这样INSERT
语句增加一条新记录:
mysql> INSERT INTO pet -> VALUES ('Puffball','Diane','hamster','f','1999-03-30',NULL);
注意,这里字符串和日期值被指定为引号扩起来的字符串。另外,用INSERT
,你能直接插入NULL
代表不存在的值。你不能使用\N
,就像你用LOAD DATA
做的那样。
从这个例子,你应该能看到涉及很多的键入用多个INSERT
语句而非单个LOAD DATA
语句装载你的初始记录。
SELECT
语句被用来从一张桌子拉出信息。语句的一般格式是:
SELECT what_to_select FROM which_table WHERE conditions_to_satisfy
what_to_select
指出你想要看到的,这可以是列的一张表,或*
表明“所有的列”。which_table
指出你想要从其检索数据的表。WHERE
子句是可选的,如果它在,conditions_to_satisfy
指定行必须满足的检索条件。
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 | 1998-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,而不是1998。
至少有一些修正它的方法:
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";
如上所示,检索整个表是容易的,但是一般你不想那样做,特别地当表变得很大时。相反,你通常对回答一个特别的问题更感兴趣,在这种情况下你在你想要的信息上指定一些限制。让我们看一些他们回答有关你宠物的问题的选择查询。
你能从你的表中只选择特定的行。例如,如果你想要验证你对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,而不是1998。
字符串比较通常是大小些无关的,因此你可以指定名字为"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
可以混用。如果你这样做,使用括号指明条件应该如何被分组是一个好主意:
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 | +-------+--------+---------+------+------------+-------+
如果你不想要看到你的表的整个行,就命名你感兴趣的列,用逗号分开。例如,如果你想要知道你的动物什么时候出生的,精选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 | +--------+---------+------------+
你可能已经注意到前面的例子中结果行没有以特定的次序被显示。然而,当行以某个有意义的方式排序,检验查询输出通常是更容易的。为了排序结果,使用一个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 | +----------+------------+
为了以逆序排序,增加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
值仍然以升序被排序。