引用
这一章提供 MySQL 教程介绍通过展示如何使用mysql客户端程序来创建和使用一个简单的数据库。 mysql (有时称为"终端监视器"或只是"监视器") 是一个交互式的程序,使您能够连接到 MySQL 服务器,运行查询,并查看结果。mysql也可用在批处理模式下︰ 首先,在文件中放置您的查询,然后告诉mysql执行该文件的内容。
若要查看由mysql所提供的选项列表,调用它与--help
选项︰
shell> mysql --help
本章假定您计算机上安装的mysql和 MySQL 服务器可用的,您可以连接到。
这一章描述设置和使用数据库的整个的过程。如果你有兴趣只是在访问现有的数据库,你可跳过。
需要 MySQL 用户名称,主机地址,密码
shell>mysql -h
Enter password:host
-uuser
-p********
host
和user
代表在运行你的 MySQL 服务器的主机名和您的 MySQL 帐户的用户名称 ********
表示您的密码;
当mysql显示输入Enter password: 输入密码
如果成功,你应该看到一些介绍性的信息,其次是mysql>
提示︰
shell>mysql -h
Enter password:host
-uuser
-p********
Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 25338 to server version: 5.6.26-standard Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql>
mysql>
提示告诉您, mysql是准备好您输入命令。
如果 MySQL 运行本机,你可以省略主机,并只需使用以下内容︰
shell> mysql -u user
-p
如果当您尝试登录,你得到一条错误消息如错误 2002 (HY000): 无法连接到本地的 MySQL 服务器,通过套接字 '/tmp/mysql.sock',这意味着, MySQL 服务器守护进程 (Unix) 或服务 (Windows)没有启动。
成功连接后,您可以通过在键入QUIT
(或\q
) 断开
提示︰
mysql> QUIT
Bye
在 Unix 上,可以通过按控制 + D 断开。
以下各节中的大多数示例假设您连接到服务器。他们表示这由mysql>
提示符。
确保您连接到服务器上,如前一节所述。
这里是一个简单的命令,要求服务器来告诉你它的版本号,当前日期。此处所示后请将其键入mysql>
提示并按 enter 键︰
mysql> SELECT VERSION(), CURRENT_DATE;
+--------------+--------------+
| VERSION() | CURRENT_DATE |
+--------------+--------------+
| 5.6.1-m4-log | 2010-08-06 |
+--------------+--------------+
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.6.1-m4-log |
+--------------+
1 row in set (0.00 sec)
+---------------------+
| NOW() |
+---------------------+
| 2010-08-06 12:17:13 |
+---------------------+
1 row in set (0.00 sec)
命令不一定要所有在同一行上,所以需要几行的冗长的命令不是一个问题。 mysql确定在哪里你的发言结束通过寻找终止分号,而不是通过寻找输入行的结尾。(换句话说, mysql接受自由格式输入︰ 它收集输入的线,但不是执行他们直到它认为分号。)
这里是一个简单的多行语句︰
mysql>SELECT
->USER()
->,
->CURRENT_DATE;
+---------------+--------------+ | USER() | CURRENT_DATE | +---------------+--------------+ | jon@localhost | 2010-08-06 | +---------------+--------------+
在此示例中,请注意如何提示更改从mysql>
到->
后你输入多行查询的第一行。这是mysql如何表示自己还没有看到一个完整的语句,它等待其余部分。在提示符下是你的朋友,因为它提供了有价值的反馈。如果您使用的反馈,你总是可以意识到什么mysql等待。
如果您决定您不想执行一个命令,你正在进入,取消它通过键入\c
:
mysql>SELECT
->USER()
->\c
mysql>
在这里,太,通知提示。切换回mysql>
键入\c
后,提供反馈,以表明, 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
的行。这可以相当混乱,尤其是如果你不知道,你需要提供终止报价之前你可以取消当前命令。
一旦你知道如何输入命令,你就可以访问数据库。
假设你有几个宠物在家里 (您的动物园) 和你想要跟踪的各种类型的关于他们的信息。你可以通过创建表来保存您的数据并加载它们与所需的信息。然后你可以通过从表中检索数据,关于你的动物回答不同种类的问题。本节说明了如何执行以下操作︰
创建数据库
创建一个表
将数据加载到表
从以各种方式表中检索数据
使用多个表
动物园数据库是简单 (故意),但它是不难想象的真实世界的情况,可能会用一种类似的数据库。例如,一位农民来跟踪牲畜,或由一名兽医,跟踪病人的记录,可以用这样一个数据库。从 MySQL Web 站点可以获得包含查询和使用在以下各节中的示例数据的一些动物园分布。这是可在压缩的tar文件和 Zip 格式在http://dev.mysql.com/doc/.
使用SHOW
语句来找出哪些数据库当前存在于服务器上︰
mysql> SHOW DATABASES;
+----------+
| Database |
+----------+
| mysql |
| test |
| tmp |
+----------+
mysql
数据库描述了用户访问权限。test
数据库通常是可用作工作区的用户尝试的事情。
数据库中的语句所显示的列表,会有不同的您的机器;SHOW DATABASES
不显示您有没有权限的数据库是否你没有SHOW DATABASES
特权。请参阅一节 13.7.5.15"显示数据库的语法".
如果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
是分配给你和your_client_host
的 MySQL 用户名称是从中你连接到服务器的主机。
如果管理员为您创建您的数据库,设置您的权限时,您可以开始使用它。否则,您需要自己创建它︰
mysql> CREATE DATABASE menagerie;
Unix 下,数据库名称是区分大小写 (不像 SQL 关键字),所以你必须总是请参阅您的数据库作为menagerie
,而不是Menagerie
,MENAGERIE
或一些其他变种。这也是真实的表名。(根据 Windows,这种限制不适用于,虽然你必须引用数据库和表使用相同的 lettercase,整个一个给定的查询。然而,对于各种原因,建议的最佳做法是始终使用时创建数据库使用了相同的 lettercase。)
如果你得到一个错误如错误 1044 (42000): 访问被拒绝用户对数据库 '动物园' ' monty'@'localhost'当试图创建数据库,这意味着您的用户帐户并没有这样做的必要权限。与管理员讨论这问题,或看到第 6.2 节,"MySQL 访问特权系统".
创建数据库不会选择它的使用;你必须明确。若要使menagerie
当前数据库,请使用以下命令︰
mysql> USE menagerie
Database changed
您的数据库需要将只创建一次,但你必须选择它以便使用每个mysql会话开始的时间。你可以通过发行USE
语句在示例中所示。或者,你可以选择命令行上的数据库,当您调用mysql时。只是之后你可能需要提供任何连接参数指定其名称。例如︰
shell>mysql -h
Enter password:host
-uuser
-p menagerie********
menagerie
只是显示的命令中是没有您的密码。如果您想要您提供的密码在命令行上使用-p
选项后,你必须这样做与不干预的空间 (例如,作为-pmypassword
,而不是-p mypassword
)。然而,将你的密码放在命令行上不是推荐,因为做所以它暴露窥探的登录您的计算机上的其他用户。
你可以随时查看哪个数据库当前选定使用SELECT
DATABASE()
.
创建数据库是比较容易的部分,但在这一点上它是空的如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'
.
DATE
数据类型用于的birth
和death
的列是一个显而易见的选择。
一旦你创建了一个表,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
任何时间,例如,如果您忘记了的列的名称在你的桌子或什么类型的他们有。
有关 MySQL 数据类型的详细信息,请参阅第 11 章,数据类型.
创建自己的表之后, 你需要填充它。LOAD DATA
和INSERT
语句为此是有用。
假设,可以描述你宠物的记录,如下所示。(观察 MySQL 预计日期'YYYY-MM-DD'
格式; 这可能不同于你所习惯。)
名称 | 主人 | 物种 | 性别 | 出生 | 死亡 |
---|---|---|---|---|---|
蓬松 | 哈罗德 · | 猫 | f | 1993-02-04 | |
利爪 | 格温 | 猫 | m | 1994-03-17 | |
巴菲 | 哈罗德 · | 狗 | f | 1989-05-13 | |
芳 | 本尼 | 狗 | m | 1990-08-27 | |
鲍泽 | 黛安 | 狗 | m | 1979-08-31 | 1995-07-29 |
嘁嘁喳喳地 | 格温 | 鸟 | f | 1998-09-11 | |
惠斯勒 | 格温 | 鸟 | 1997-12-09 | ||
苗条的 | 本尼 | 蛇 | m | 1996-04-29 |
因为你开始与一个空表,简单的方法来填充它是创建一个文本文件,包含行每个你的动物,然后将文件的内容加载到与单个语句表。
您可以创建文本文件pet.txt
,每条记录占一行,含值隔开选项卡,并给出了在其中包括CREATE TABLE
语句中列出的列的顺序。对于缺少的值 (如未知的性别或都健在的动物的死亡日期),您可以使用NULL
值。代表这些文本文件中,请使用\N
(反斜杠,资本-N)。例如,惠斯勒鸟记录将如下所示 (其中值之间的空格是单个制表符)︰
Whistler Gwen bird \N 1997-12-09 \N
要加载到pet
表文本文件pet.txt
,请使用以下语句︰
mysql> LOAD DATA LOCAL INFILE '/path/pet.txt' INTO TABLE pet;
如果您使用使用\r\n
作为行终止符编辑器创建该文件在 Windows,您应改用此语句︰
mysql>LOAD DATA LOCAL INFILE '/path/pet.txt' INTO TABLE pet
->LINES TERMINATED BY '\r\n';
(在运行 OS X 苹果机,您可能希望使用LINES TERMINATED BY '\r'
.)
你可以列值分隔符和的行尾标记显式的语句中指定LOAD DATA
如果你希望,但默认设置制表符和换行符。这些都是足够的语句来正确读取文件pet.txt
。
如果该语句将失败,很可能你的 MySQL 安装没有本地文件功能默认启用的。有关如何更改此信息,请参阅第 6.1.6 条,"安全问题与负载数据本地"。
当你想要一次添加一个新记录时, INSERT
语句是有用的。最简单的形式,提供为每个列,其中包括CREATE TABLE
语句中列出的列的顺序的值。假设黛安娜获取新的仓鼠,命名为"马勃菌。"您可以添加新记录使用INSERT
语句,像这样︰
mysql>INSERT INTO pet
->VALUES ('Puffball','Diane','hamster','f','1999-03-30',NULL);
字符串和日期值被指定为带引号的字符串在这里。此外,与INSERT
,你可以插入NULL
直接表示缺少的值。你不使用\N
,就象你LOAD DATA
.
从这个例子中,你应该能够看到会有更多的录入涉及加载您最初使用几个INSERT
语句,而不是单个LOAD DATA
语句的记录。
SELECT
语句用于从表中提取信息。该语句的一般形式为︰
SELECTwhat_to_select
FROMwhich_table
WHEREconditions_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 | 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
是有用的如果您想要查看整个表格,例如之后你刚刚装它与初始数据集。例如,你可能会这样想鲍泽的出生日期不太对劲吧。你咨询你原始的谱系论文,找到正确的出生年份应 1989年,不 1979年。
有至少两种方法来解决此问题︰
编辑文件pet.txt
更正错误,然后空表,然后重新加载它使用DELETE
和LOAD DATA
:
mysql>DELETE FROM pet;
mysql>LOAD DATA LOCAL INFILE 'pet.txt' INTO TABLE pet;
然而,如果你这样做,你还必须重新输入记录的马勃菌。
用UPDATE
语句修复只有错误的记录︰
mysql> UPDATE pet SET birth = '1989-08-31' WHERE name = 'Bowser';
UPDATE
更改只记录问题,并且不需要您重新加载表。
如前一节中所示,它很容易检索整个表。只需省略从SELECT
语句的WHERE
子句。但通常,你不想看到整个表,特别是当它变得大。相反,你通常更有兴趣回答特定的问题,在这种情况下,您指定一些约束上你想要的信息。让我们看看一些关于你的宠物,他们回答的问题的选择查询。
你可以从你的表选择只有特定行。例如,如果您想要验证所做的更改对鲍泽的出生日期,选择这样的鲍泽的记录︰
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 | +-------+--------+---------+------+------------+-------+
如果你不想看到你的表中的整行,只是名称的列,感兴趣的你,以逗号分隔。例如,如果你想要知道你的动物出生的时候,选择的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 |
+----------+------------+
字符类型列,排序上 — — 像所有其他比较操作 — — 通常在不区分大小写的方式下进行。这意味着的顺序是未定义的列都是相同的除了他们的案件。您可以通过使用BINARY
强制区分大小写的排序的列如下所示︰ORDER BY BINARY
.col_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
列的排序顺序。
MySQL 提供了几个函数,您可以使用来对日期执行计算,例如,以计算年龄或提取的日期部分。
每个你的宠物是,以确定多少岁,使用TIMESTAMPDIFF()
函数。其参数是结果表示,单位和对其采取区别这两个日期。下面的查询显示,每个宠物、 出生日期、 当前日期和年龄的年数。别名(age
) 用来使最终的输出列标签更有意义。
mysql>SELECT name, birth, CURDATE(),
->TIMESTAMPDIFF(YEAR,birth,CURDATE()) 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 | +----------+------------+------------+------+
查询的工作,但结果可能会扫描更多容易如果行了一些订单。这可以通过添加一个ORDER BY name
子句,以便按名称排序输出︰
mysql>SELECT name, birth, CURDATE(),
->TIMESTAMPDIFF(YEAR,birth,CURDATE()) 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(),
->TIMESTAMPDIFF(YEAR,birth,CURDATE()) 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
值,计算的birth
与death
的值之间的差异︰
mysql>SELECT name, birth, death,
->TIMESTAMPDIFF(YEAR,birth,death) 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"使用空值".
如果你想知道哪些动物有下个月的生日吗?对于此类型,一年和一天是计算的无关紧要的;你只是想要提取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 月。你只是不能添加一个为月数 (12
) 并寻找动物出生于月13
,因为那里是没有这种一个月。相反,你寻找动物生于一月 (月1
).
您可以编写查询,从而使它工作无论当前月份,这样你不需要用一个特定的月数。 DATE_ADD()
使您能够添加到给定的日期的时间间隔。如果您将一个月添加到CURDATE()
的值,然后提取与MONTH()
的月部分,结果生产从中查找生日的月份︰
mysql>SELECT name, birth FROM pet
->WHERE MONTH(birth) = MONTH(DATE_ADD(CURDATE(),INTERVAL 1 MONTH));
不同的方式来完成相同的任务是要加1
以获取下一个月的后使用当前一个模函数 (MOD
) 来包装的月份值为0
,如果它是目前12
:
mysql>SELECT name, birth FROM pet
->WHERE MONTH(birth) = MOD(MONTH(CURDATE()), 12) + 1;
MONTH()
返回1
到12
之间的一个数字。 MOD(something,12)
返回一个数字0
到11
之间。所以除了必须后MOD()
,否则我们会去从 11 月 (11
) 1 (1
月).
直到你习惯了它,可以令人惊讶中的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 |
+-----------+---------------+
您不能使用如=
、 <
或<>
的算术比较运算符来测试为NULL
。要为自己证明这一点,请尝试下面的查询︰
mysql> SELECT 1 = NULL, 1 <> NULL, 1 < NULL, 1 > NULL;
+----------+-----------+----------+----------+
| 1 = NULL | 1 <> NULL | 1 < NULL | 1 > NULL |
+----------+-----------+----------+----------+
| NULL | NULL | NULL | NULL |
+----------+-----------+----------+----------+
因为任何算术与NULL
比较的结果也是NULL
的你不能从这种比较获得任何有意义的结果。
在 MySQL、 0
或NULL
虚假和别的意味着真实。从布尔操作的默认真值是1
.
这个NULL
的特殊待遇是甚么,在前面的部分中,它有必要确定哪些动物是不再活着使用death IS NOT NULL
,而不death <> NULL
.
两个NULL
值被视为相等的GROUP BY
.
时做ORDER BY
,NULL
值给出了第一如果你 ORDER BY ORDER BY ... ASC
和最后如果你 ORDER BY ORDER BY ... DESC
.
使用NULL
时的常见错误是假定它不可能定义为NOT NULL
列中插入零或空字符串,但情况并非如此。这些都是值,而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
的列,作为这些其实是NOT NULL
。请参阅一节 B.5.5.3"与空值问题".
MySQL 提供了标准的 SQL 模式匹配以及基于扩展正则表达式类似于所使用的 Unix 实用程序如vi、 grep和sed的模式匹配的一种形式.
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
模式匹配,成功只当模式匹配整个值)。
锚定一个模式以便它必须匹配的开头或结尾的正在进行测试的值,请使用"^
"开头或"$
"在模式的结尾。
演示如何扩展正则表达式的工作,所示的LIKE
查询以前不会重写在这里要使用REGEXP
.
若要查找以"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 个字符的名称,请使用"^
"和"$
"来匹配的开头和结尾的名称和".
"之间的五个实例︰
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 |
+-------+--------+---------+------+------------+-------+
12.5.2,"正则表达式"一节中,提供有关正则表达式的语法的详细信息。
数据库通常用来回答这个问题, "某种类型的数据出现在表中频率?"例如,你可能想要知道你有多少宠物多少宠物每个所有者有,或者你可能想要执行各种普查业务上你的动物。
计数的动物你有总数是相同的问题"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
的所有记录进行分组。与GROUP BY
一起使用COUNT()
是用于描述您的数据在各个集团。下面的示例演示不同的方式来执行动物普查活动。
每个物种的动物的数量︰
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 | +---------+------+----------+
如果你的名字列除COUNT()
值要选择, GROUP BY
子句应的礼物,那些相同的列的名称。否则,将发生以下情况︰
如果启用了ONLY_FULL_GROUP_BY
SQL 模式,将产生错误︰
mysql>SET sql_mode = 'ONLY_FULL_GROUP_BY';
Query OK, 0 rows affected (0.00 sec) 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
如果未启用ONLY_FULL_GROUP_BY
,查询处理的所有行都视为单个组,但值选定的每个命名的列是不确定的。服务器可以自由地从任何行选择的值︰
mysql>SET sql_mode = '';
Query OK, 0 rows affected (0.00 sec) mysql>SELECT owner, COUNT(*) FROM pet;
+--------+----------+ | owner | COUNT(*) | +--------+----------+ | Harold | 8 | +--------+----------+ 1 row in set (0.00 sec)
参见第 12.19.3 节,"MySQL 处理的 GROUP BY".
pet
表跟踪的你所拥有的宠物。如果你想要记录其他信息,如像访问到兽医或当凋落物天生的他们生活中的事件则需要另一个表。这表看起来应该像什么?它需要包含以下信息︰
这个宠物的名字,你知道哪种动物的每个事件涉及到。
A 日期,你知道事件何时发生。
字段描述事件。
事件类型字段,如果你想要能够对事件进行分类。
鉴于这些考量,event
表的CREATE TABLE
语句可能如下所示︰
mysql>CREATE TABLE event (name VARCHAR(20), date DATE,
->type VARCHAR(15), remark VARCHAR(255));
与pet
表一样,它是最容易通过创建包含以下信息的选项卡分隔的文本文件中加载初始记录。
名称 | 日期 | 类型 | 备注 |
---|---|---|---|
蓬松 | 1995-05-15 | 垃圾 | 4 只小猫,3 女 1 男 |
巴菲 | 1993-06-23 | 垃圾 | 5 只小狗,2 女 3 男 |
巴菲 | 1994-06-19 | 垃圾 | 3 只小狗,3 女 |
嘁嘁喳喳地 | 1999-03-21 | 兽医 | 所需的喙直 |
苗条的 | 1997-08-03 | 兽医 | 肋骨 |
鲍泽 | 1991-10-12 | 狗窝 | |
芳 | 1991-10-12 | 狗窝 | |
芳 | 1998-08-28 | 生日 | 送给他一个新的咀嚼玩具 |
利爪 | 1998-03-17 | 生日 | 给了他一个新的跳蚤项圈 |
惠斯勒 | 1998-12-09 | 生日 | 第一个生日 |
加载的像这样的记录︰
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)
->remark
->FROM pet INNER JOIN event
->ON pet.name = event.name
->WHERE 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
列。该查询使用ON
子句来匹配基于name
的值的两个表中的记录。
查询使用INNER JOIN
将表组合。INNER JOIN
允许从任意一个表,则结果中显示,当且仅当两个表满足ON
子句中指定的条件的行。在此示例中, ON
子句指定在pet
表中的name
列必须匹配的event
表中的name
列。如果名称出现在一个表,但不是其他,该行将不出现在结果因为在ON
子句中的条件失败。
name
列在这两个表中出现,因为你必须具体说明你的意思是当谈到列的表。这是通过在表名称的列的名称前面。
你不需要有两个不同的表以执行联接。有时很有用的表联接到本身,如果你想要比较其他同一表中的记录的表中的记录。例如,要查找繁殖对你的宠物之一,可以加入与本身产生候选人对雄性和雌性的物种像pet
表︰
mysql>SELECT p1.name, p1.sex, p2.name, p2.sex, p1.species
->FROM pet AS p1 INNER JOIN pet AS p2
->ON 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 | +--------+------+--------+------+---------+
在此查询中,我们指定要引用的列和保持直哪个实例与关联的每个列引用的表的表名的别名。
如果你忘记了名称的数据库或表,或给定的表的结构 (例如,其列中称为) 是什么?MySQL 解决这个问题通过提供有关数据库和它支持的表的信息的几个语句。
你以前见过SHOW DATABASES
,其中列出了由服务器管理的数据库。要找出当前选定的数据库,请使用DATABASE()
函数︰
mysql> SELECT DATABASE();
+------------+
| DATABASE() |
+------------+
| menagerie |
+------------+
如果未选择任何数据库,则结果为NULL
.
要找出哪些表的默认数据库包含 (例如,当你不是对表的名称),请使用以下命令︰
mysql> SHOW TABLES;
+---------------------+
| Tables_in_menagerie |
+---------------------+
| event |
| pet |
+---------------------+
此语句所生成的输出中的名称始终是数据库的列的Tables_in_
、db_name
db_name
哪里的名称。有关更多信息,请参见第 13.7.5.38 条,显示表的"语法"。
如果你想要找出关于表的结构,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
指示Key
是否列可以包含NULL
值,指示是否对列创建索引,并Default
指定列的默认值。Extra
的显示列的特别信息︰ 如果使用AUTO_INCREMENT
选项创建一个列,值将被auto_increment
,而不是空的。
DESC
是DESCRIBE
的缩写形式。有关更多信息,请参见第 13.8.1 节,描述的"语法"。
您可以获得必要创建现有的表使用SHOW CREATE TABLE
语句的CREATE TABLE
语句。请参阅一节 13.7.5.12"显示创建表语法".
如果你的表上有索引,SHOW INDEX FROM
生产有关它们的信息。关于此语句的更多信息,请参阅13.7.5.23,"显示索引语法"一节。tbl_name
在前面的章节中,你使用mysql以交互方式输入查询并查看结果。您还可以在批处理模式下运行mysql 。要做到这一点,把你想要在文件中,运行的命令,然后告诉mysql从文件中读取其输入︰
shell> mysql < batch-file
如果你在 Windows 下运行mysql ,有一些特殊的字符,文件中导致的问题,你可以这样做︰
C:\> mysql -e "source batch-file
"
如果你需要在命令行上指定连接参数,该命令可能如下所示︰
shell>mysql -h
Enter password:host
-uuser
-p <batch-file
********
当你通过这种方式使用mysql时,您是创建脚本文件,然后执行该脚本。
如果你想要继续,即使一些中它的语句产生错误的脚本,您应该使用--force
命令行选项。
为什么使用脚本吗?这里有几个原因︰
如果你反复运行一个查询,(说,每天或每周),使它的脚本使您能够避免重新键入每次你执行它。
您可以从现有那些类似通过复制和编辑脚本文件生成新的查询。
批处理模式也可以有用,而你正在开发一个查询,特别是对多行命令或多语句序列的命令。如果你犯了错,你不必重新键入所有内容。只需编辑您的脚本以更正错误,然后告诉mysql若要再次执行它。
如果你有一个产生大量输出的查询,您可以通过一部传呼机,而不是看它掉你的屏幕的顶部滚动运行的输出︰
shell> mysql < batch-file
| more
您可以捕获中作进一步处理文件的输出︰
shell> mysql < batch-file
> mysql.out
所以,他们也可以运行命令,您可以分发您的脚本给其他人。
某些情况下不允许交互使用,例如,当你从一个cron作业运行查询。在这种情况下,您必须使用批处理模式。
默认输出格式是不同的 (更简洁) 当你运行mysql在批处理模式下比当您以交互方式使用它。例如,SELECT DISTINCT species FROM pet
的输出看起来像这样以交互方式运行mysql时︰
+---------+ | species | +---------+ | bird | | cat | | dog | | hamster | | snake | +---------+
在批处理模式下,输出反而看起来像这样︰
species bird cat dog hamster snake
如果你想要在批处理模式中得到交互输出格式,使用mysql -t
。回显到输出执行的命令,请使用mysql -vvv
.
你也可以使用脚本从mysql提示通过使用source
命令或\.
命令︰
mysql>source
mysql>filename
;\.
filename
有关更多信息,请参见第 4.5.1.5 条,"执行 SQL 语句的文本文件"。
这里是如何解决一些常见的问题与 MySQL 的例子。
一些例子使用表shop
举行的每一篇文章 (物料编号) 价格为某些交易者 (经销商)。每个交易者都 (article
、dealer
) 单一固定的价格每篇文章,然后派上用场是主键的记录。
启动mysql命令行工具并选择数据库︰
shell> mysql your-database-name
(在大多数的 MySQL 安装,您可以使用名为test
的数据库).
您可以创建和填充这些语句的示例表︰
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 | +---------+
任务︰ 找到的号码,经销商和最昂贵的商品的价格。
这是容易做到的子查询︰
SELECT article, dealer, price FROM shop WHERE price=(SELECT MAX(price) FROM shop); +---------+--------+-------+ | article | dealer | price | +---------+--------+-------+ | 0004 | D | 19.95 | +---------+--------+-------+
其他的解决办法是使用一个LEFT JOIN
或降序按价格的所有行进行都排序,得到仅第一行使用 MySQL 特定LIMIT
子句︰
SELECT s1.article, s1.dealer, s1.price FROM shop s1 LEFT JOIN shop s2 ON s1.price < s2.price WHERE s2.article IS NULL; 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 | +---------+-------+
任务︰ 每篇文章,找到供货商或经销商的最昂贵的价格。
这个问题可以解决像这样子查询︰
SELECT article, dealer, price FROM shop s1 WHERE price=(SELECT MAX(s2.price) FROM shop s2 WHERE s1.article = s2.article); +---------+--------+-------+ | article | dealer | price | +---------+--------+-------+ | 0001 | B | 3.99 | | 0002 | A | 10.99 | | 0003 | C | 1.69 | | 0004 | D | 19.95 | +---------+--------+-------+
前面的示例可以是效率低下 (见第 13.2.10.7 条,"相关子查询") 的相关子查询。其他解决问题的可能性是使用FROM
子句或LEFT JOIN
不相关子查询.
不相关子查询︰
SELECT s1.article, dealer, s1.price FROM shop s1 JOIN ( SELECT article, MAX(price) AS price FROM shop GROUP BY article) AS s2 ON s1.article = s2.article AND s1.price = s2.price;
LEFT JOIN
:
SELECT s1.article, s1.dealer, s1.price FROM shop s1 LEFT JOIN shop s2 ON s1.article = s2.article AND s1.price < s2.price WHERE s2.article IS NULL;
LEFT JOIN
工程基础s1.price
在其最大值时,还有没有更大的价值的s2.price
和s2
行值将为NULL
。请参阅"加入语法"一节 13.2.9.2,.
您可以使用 MySQL 用户变量,要记住结果,而不必将它们存储在客户端中的临时变量。(请参见第 9.4 节、"用户定义的变量".)
例如,要查找物品的最高和最低的价格可以执行这︰
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 | +---------+--------+-------+
它也是可能在用户变量中存储的数据库对象,如表或列名称,然后再使用此变量中的 SQL 语句;然而,这需要使用预准备语句。有关更多信息,请参见13.5 节,"准备语句的 SQL 语法"。
在 MySQL, InnoDB
表支持外键约束的检查。见章 14, InnoDB 存储引擎,和部分 1.8.2.3、"外国关键差异".
外键约束不被要求只是联接两个表。为非InnoDB
存储引擎,它是可能定义要使用一个REFERENCES
条款,没有实际效果,只充当备注或评论给你您当前定义的列是打算引用另一个表中的列的列时。它是极为重要的是要意识到使用此语法时,︰tbl_name
(col_name
)
MySQL 不执行任何种类的CHECK
以确保col_name
实际上存在于tbl_name
(或甚至那tbl_name
本身存在)。
MySQL 不执行任何类型的操作上tbl_name
如删除行在响应您定义; 表中的行采取的操作换句话说,这种语法诱使任何没有ON DELETE
或ON UPDATE
行为。(虽然你可以编写一个ON DELETE
或ON UPDATE
子句REFERENCES
子句的一部分,它也将忽略。)
此语法创建一列;它并不创建任何类型的索引或键。
您可以使用作为联接列,所以创建的列,如下所示︰
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 INNER JOIN shirt s ON s.owner = p.id WHERE p.name LIKE 'Lilliana%' 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
表。
OR
使用单一密钥是很好的优化,是处理AND
.
一个棘手案件就是根据两个不同的键结合OR
搜索:
SELECT field1_index, field2_index FROM test_table WHERE field1_index = '1' OR field2_index = '1'
这种情况下进行了优化。请参阅8.2.1.4 节"索引合并优化".
也可以通过使用一个UNION
,结合两个单独的SELECT
语句的输出有效地解决问题。请参阅一节 13.2.9.3"联盟的语法".
每个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';
下面的示例演示如何使用位组函数来计算的天数每月用户访问过的 Web 页。
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<返回结果︰
+------+-------+------+ | year | month | days | +------+-------+------+ | 2000 | 01 | 3 | | 2000 | 02 | 2 | +------+-------+------+查询计算多少不同天出现每年/每月结合,自动删除的重复条目的表中。
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 | +----+---------+
所以 MySQL 自动分配的序列号为AUTO_INCREMENT
列中,指定没有价值。此外明确可以将 0 分配给要生成序列号的列。如果列声明NOT NULL
,它也是可以将NULL
赋值给要生成序列号的列。当你插入AUTO_INCREMENT
列中任何其他值时,列设置为值和顺序置,以便下一步自动生成的值如下顺序从插入的值。
您可以检索最新的自动生成的AUTO_INCREMENT
值与LAST_INSERT_ID()
SQL 函数或mysql_insert_id()
C API 函数。这些函数是特定于连接的所以它们的返回值不受另一个连接,也执行插入。
为AUTO_INCREMENT
列即足以容纳的最大序列值,您将需要使用的最小整数数据类型。当列达到上限的数据类型时,接下来尝试生成序列号码失败。如果可能的话使用UNSIGNED
属性以允许更大的范围。例如,如果您使用TINYINT
,最大可允许序列号是 127。 TINYINT UNSIGNED
,最大值为 255。见节 11.2.1,"整数类型 (精确值)-整数、 MEDIUMINT、 INT、 TINYINT、 SMALLINT BIGINT"为所有整数类型的范围。
多行插入、LAST_INSERT_ID()
和mysql_insert_id()
其实从第一次插入的行返回AUTO_INCREMENT
键。这将启用多行插入,以在复制安装程序中的其他服务器上正确地再现。
开始于 1, AUTO_INCREMENT
值设置该值与CREATE TABLE
或ALTER TABLE
,像这样︰
mysql> ALTER TABLE tbl AUTO_INCREMENT = 100;
对于InnoDB
表,要小心,如果你修改包含在一个INSERT
语句序列的自动增量值的列。例如,如果您使用一个UPDATE
语句,一个新的更大的值放入自动增量列,随后INSERT
可能会遇到"重复的条目"的错误。测试是否自动增量的值已存在发生如果你做DELETE
其后更多的INSERT
语句,或者当你COMMIT
事务,但不是经过UPDATE
的声明。
对于MyISAM
表,您可以指定多列索引中的二次列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) ) ENGINE=MyISAM; 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
的信息在这里︰
如何将AUTO_INCREMENT
属性分配给列:第 13.1.17 条,创建表的"语法",和第 13.1.7 节、 改变表的"语法".
AUTO_INCREMENT
根据NO_AUTO_VALUE_ON_ZERO
SQL 模式的行为︰第 5.1.7 条,"服务器 SQL 模式".
如何使用LAST_INSERT_ID()
功能来查找包含最新的AUTO_INCREMENT
值的行︰节 12.14、"信息功能".
设置要使用的AUTO_INCREMENT
值︰ 5.1.4 节,"服务器系统变量".
AUTO_INCREMENT
和复制︰ 17.4.1.1 节,"复制和 AUTO_INCREMENT".
与有关的AUTO_INCREMENT
(auto_increment_increment
和auto_increment_offset
),可以用于复制服务器系统变量︰第 5.1.4 条,"服务器系统变量".
有让你你从一个 MySQL 数据库的用户进行身份验证,也让您将您的日志文件写入到一个 MySQL 表的程序。
您可以更改要将以下放入 Apache 配置文件都可以很容易读取 MySQL 的 Apache 日志记录格式︰
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 TABLEtbl_name
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '\\'
应创建命名的表有对应的LogFormat
行写入日志文件的那些列。