目录
本章通过展示如何使用 mysql 客户端程序创建和使用简单数据库 来提供MySQL的教程介绍 。 mysql (有时称为 “ 终端监视器 ” 或只是 “ 监视器 ” )是一个交互式程序,使您可以连接到MySQL服务器,运行查询和查看结果。 mysql 也可以在批处理模式下使用:事先将查询放在文件中,然后告诉 mysql 执行文件的内容。 这里介绍 了使用 mysql的 两种方法 。
要查看
mysql
提供的选项列表,请
使用以下
--help
选项
调用它
:
外壳> mysql --help
本章假设 MySQL的 安装在您的机器上,以及一个MySQL服务器是提供给你可以连接。 如果不是这样,请联系您的MySQL管理员。 (如果 您 是管理员,则需要查阅本手册的相关部分,例如 第5章, MySQL服务器管理 。)
本章介绍了设置和使用数据库的整个过程。 如果您只对访问现有数据库感兴趣,则可能需要跳过描述如何创建数据库及其包含的表的部分。
因为本章本质上是教程,所以必须省略许多细节。 有关此处所涉及主题的更多信息,请参阅手册的相关章节。
要连接到服务器,通常需要在调用 mysql 时提供MySQL用户名, 并且很可能是密码。 如果服务器在您登录的计算机以外的计算机上运行,则还需要指定主机名。 请与您的管理员联系,以了解您应该使用哪些连接参数进行连接(即,要使用的主机,用户名和密码)。 一旦知道了正确的参数,就应该能够像这样连接:
shell> 输入密码:mysql -h
host
-uuser
-p********
host
并
user
表示运行MySQL服务器的主机名和MySQL帐户的用户名。
替换适合您的设置的值。
该
********
代表你的密码;
当
mysql
显示
Enter
password:
提示
时输入它
。
如果可行,您应该看到一些介绍性信息,然后是
mysql>
提示:
shell> 输入密码:mysql -h
host
-uuser
-p********
欢迎使用MySQL监视器。命令以;结尾; 或\ g。 您的MySQL连接ID是25338到服务器版本:8.0.18-standard 输入'help;' 或'\ h'寻求帮助。输入'\ c'清除缓冲区。 MySQL的>
该
mysql>
提示告诉你
的mysql
准备为你输入SQL语句。
如果您在运行MySQL的同一台计算机上登录,则可以省略主机,只需使用以下命令:
外壳> mysql -u user
-p
如果,当您尝试登录时,会收到错误消息,例如 ERROR 2002(HY000):无法通过套接字'/tmp/mysql.sock'(2)连接到本地MySQL服务器 ,这意味着MySQL服务器守护程序(Unix)或服务(Windows)未运行。 请咨询管理员或参阅 适用于您的操作系统 的 第2章“ 安装和升级MySQL ”一节 。
有关尝试登录时经常遇到的其他问题的帮助,请参见 第B.4.2节“使用MySQL程序时的常见错误” 。
某些MySQL安装允许用户以匿名(未命名)用户身份连接到本地主机上运行的服务器。 如果你的机器上是这种情况,你应该可以通过调用 没有任何选项的 mysql 连接到该服务器 :
外壳> mysql
成功连接后,您可以通过
在
提示符
下键入
QUIT
(或
\q
)
来随时断开连接
mysql>
:
MySQL的> QUIT
再见
在Unix上,您也可以通过按Control + D断开连接。
以下部分中的大多数示例都假定您已连接到服务器。
他们通过
mysql>
提示
表明了这一点
。
确保已连接到服务器,如上一节中所述。 这样做本身并不会选择任何可以使用的数据库,但这没关系。 此时,更重要的是要找到一些关于如何发布查询的信息,而不是直接创建表,将数据加载到它们中以及从中检索数据。 本节介绍了输入查询的基本原则,使用您可以尝试的几个查询来熟悉 mysql的 工作原理。
这是一个简单的查询,要求服务器告诉您它的版本号和当前日期。
按照
mysql>
提示输入
如下所示
,然后按Enter键:
MySQL的> SELECT VERSION(), CURRENT_DATE;
+ ----------- -------------- + +
| 版本()| CURRENT_DATE |
+ ----------- -------------- + +
| 5.8.0-m17 | 2015-12-21 |
+ ----------- -------------- + +
1排(0.02秒)
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排(0.02秒)
到目前为止显示的查询是相对较短的单行语句。 您甚至可以在一行中输入多个语句。 用分号结束每一个:
MySQL的> SELECT VERSION(); SELECT NOW();
+ ----------- +
| 版本()|
+ ----------- +
| 8.0.13 |
+ ----------- +
1排(0.00秒)
+ --------------------- +
| 现在()|
+ --------------------- +
| 2018-08-24 00:56:40 |
+ --------------------- +
1排(0.00秒)
不需要在一行上提供查询,因此需要多行的冗长查询不是问题。 mysql 通过查找终止分号来确定语句的结束位置,而不是查找输入行的结尾。 (换句话说, mysql 接受自由格式输入:它收集输入行但在看到分号之前不执行它们。)
这是一个简单的多行语句:
mysql>SELECT
- >USER()
- >,
- >CURRENT_DATE;
+ --------------- + -------------- + | USER()| CURRENT_DATE | + --------------- + -------------- + | jon @ localhost | 2018-08-24 | + --------------- + -------------- +
在这个例子中,请注意提示符从
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
允许您输入跨越多行的字符串。
当您看到
'>
或
">
提示时,表示您输入的行包含以a
'
或
"
引号字符
开头的字符串
,但尚未输入终止字符串的匹配引号。
这通常表明您无意中遗漏了引号字符。
例如:
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
。
这可能非常令人困惑,特别是如果您不知道在取消当前查询之前需要提供终止引用。
此时的多行语句是在没有辅助(
->
或其他)提示的
情况下编写的
,以便于复制和粘贴语句以便自己尝试。
一旦知道如何输入SQL语句,就可以访问数据库了。
假设您家中有几只宠物(您的动物园),并且您希望跟踪有关它们的各种类型的信息。 您可以通过创建表来保存数据并使用所需信息加载数据。 然后,您可以通过从表中检索数据来回答有关动物的各种问题。 本节介绍如何执行以下操作:
创建一个数据库
创建一个表
将数据加载到表中
以各种方式从表中检索数据
使用多个表
动物园数据库很简单(故意),但要想到可能使用类似数据库的真实情况并不困难。 例如,农民可以使用这样的数据库来跟踪牲畜,或者由兽医跟踪患者记录。 可以从MySQL网站获得包含以下部分中使用的一些查询和样本数据的动物园分布。 它可以 通过 https://dev.mysql.com/doc/ 以压缩 tar 文件和Zip格式提供 。
使用该
SHOW
语句查找服务器上当前存在的数据库:
MySQL的> SHOW DATABASES;
+ ---------- +
| 数据库|
+ ---------- +
| mysql |
| 测试|
| tmp |
+ ---------- +
该
mysql
数据库描述了用户访问权限。
该
test
数据库通常可作为用户工作区尝试的事情了。
声明显示的数据库列表可能与您的计算机不同;
SHOW
DATABASES
如果您没有该
SHOW
DATABASES
权限
,则不会显示您没有权限的数据库
。
请参见
第13.7.6.14节“显示数据库语法”
。
如果
test
数据库存在,请尝试访问它:
MySQL的> USE test
数据库已更改
USE
,比如
QUIT
,不需要分号。
(如果你愿意,可以用分号终止这些语句;它没有任何危害。)该
USE
语句在另一方面也是特殊的:它必须在一行上给出。
您可以使用
test
数据库(如果您有权访问它)来获取
后面
的示例,但是您在该数据库中创建的任何内容都可以被其他任何有权访问它的人删除。
因此,您可能应该要求MySQL管理员允许使用您自己的数据库。
假设你想打电话给你
menagerie
。
管理员需要执行如下语句:
MySQL的> GRANT ALL ON menagerie.* TO 'your_mysql_name'@'your_client_host';
your_mysql_name
分配给您的MySQL用户名
在哪里,
是
your_client_host
您连接到服务器的主机。
如果管理员在设置权限时为您创建数据库,则可以开始使用它。 否则,您需要自己创建它:
MySQL的> CREATE DATABASE menagerie;
在Unix下,数据库名称是区分大小写的(不像SQL关键字),所以你必须总是指到你的数据库
menagerie
,而不是
Menagerie
,
MENAGERIE
或一些其他变种。
表名也是如此。
(在Windows下,此限制不适用,但您必须在给定查询中使用相同的字母表引用数据库和表。但是,出于各种原因,建议的最佳做法始终是使用在使用时使用的相同字母。数据库已创建。)
如果您收到错误,例如 ERROR 1044(42000): 尝试创建数据库时, 用户'micah'@'localhost'拒绝访问数据库'menagerie' ,这意味着您的用户帐户没有必要的权限所以。 与管理员讨论或参见 第6.2节“访问控制和帐户管理” 。
创建数据库不会选择它来使用;
你必须明确地这样做。
要创建
menagerie
当前数据库,请使用以下语句:
MySQL的> USE menagerie
数据库已更改
您的数据库只需创建一次,但每次开始
mysql
会话
时都必须选择它才能使用
。
您可以通过发出
USE
示例中所示
的
语句
来完成此操作
。
或者,您可以在调用
mysql
时在命令行上选择数据库
。
只需在您可能需要提供的任何连接参数之后指定其名称。
例如:
shell> 输入密码:mysql -h
host
-uuser
-p menagerie********
menagerie
在刚刚显示的命令中
不是
您的密码。
如果要在
-p
选项
后的命令行上提供密码,则
必须在没有中间空间的情况下执行此操作(例如,as
,not as
)。
但是,建议不要在命令行中输入密码,因为这样做会使其暴露给在您的计算机上登录的其他用户窥探。
-p
password
-p
password
您可以随时查看当前选择使用哪个数据库
。
SELECT
DATABASE()
创建数据库很容易,但此时它是空的,
SHOW
TABLES
告诉你:
MySQL的> SHOW TABLES;
空集(0.00秒)
更难的部分是决定数据库的结构应该是什么:您需要哪些表以及每个表中应该包含哪些列。
您想要一张包含每只宠物记录的表格。
这可以称为
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
,
因为列值的长度不同。
这些列定义中的长度不必全部相同,也不必相同
。
通常,您可以选择从任何长度
到
,无论似乎是最合理的给你。
如果你选择不好而后来需要更长的字段,那么MySQL会提供一个
声明。
owner
species
20
1
65535
ALTER
TABLE
可以选择几种类型的值来表示动物记录中的性别,例如
'm'
和
'f'
,或者可能
'male'
和
'female'
。
最简单的是使用单个字符
'm'
和
'f'
。
DATE
对于
birth
和
death
列
使用
数据类型
是一个相当明显的选择。
创建表后,
SHOW
TABLES
应该产生一些输出:
MySQL的> SHOW TABLES;
+ --------------------- +
| 动物园中的表格
+ --------------------- +
| 宠物|
+ --------------------- +
要验证您的表是否按预期方式创建,请使用以下
DESCRIBE
语句:
MySQL的> DESCRIBE pet;
+ --------- + ------------- + ------ + ------ + --------- + - ----- +
| 领域| 输入| 空| 钥匙| 默认| 额外的|
+ --------- + ------------- + ------ + ------ + --------- + - ----- +
| 名字| varchar(20)| 是的| | NULL | |
| 老板| varchar(20)| 是的| | NULL | |
| 物种| varchar(20)| 是的| | NULL | |
| 性别 char(1)| 是的| | NULL | |
| 出生| 日期| 是的| | NULL | |
| 死亡| 日期| 是的| | NULL | |
+ --------- + ------------- + ------ + ------ + --------- + - ----- +
您可以随时使用
DESCRIBE
,例如,如果您忘记了表中列的名称或它们具有的类型。
有关MySQL数据类型的更多信息,请参见 第11章, 数据类型 。
创建表后,您需要填充它。
该
LOAD
DATA
和
INSERT
语句是这个有用的。
假设您的宠物记录可以如此处所示。
(观察MySQL期望
'YYYY-MM-DD'
格式的
日期
;这可能与您习惯的不同。)
名称 | 所有者 | 种类 | 性别 | 分娩 | 死亡 |
---|---|---|---|---|---|
蓬松 | 哈罗德 | 猫 | F | 1993年2月4日 | |
爪 | 格温 | 猫 | 米 | 1994年3月17日 | |
巴菲 | 哈罗德 | 狗 | F | 1989年5月13日 | |
方 | 班尼 | 狗 | 米 | 1990年8月27日 | |
鲍泽 | 黛安 | 狗 | 米 | 1979年8月31日 | 1995年7月29日 |
扢 | 格温 | 鸟 | F | 1998年9月11日 | |
惠斯勒 | 格温 | 鸟 | 1997年12月9日 | ||
瘦 | 班尼 | 蛇 | 米 | 1996年4月29日 |
因为您从空表开始,所以填充它的一种简单方法是为每个动物创建一个包含行的文本文件,然后使用单个语句将文件内容加载到表中。
您可以创建一个文本文件
pet.txt
,每行包含一个记录,其值由制表符分隔,并按照
CREATE
TABLE
语句
中列出的顺序给出
。
对于缺失值(例如未知性别或仍然生活的动物的死亡日期),您可以使用
NULL
值。
要在文本文件中表示这些,请使用
\N
(反斜杠,大写-N)。
例如,惠斯勒鸟的记录看起来像这样(值之间的空格是单个制表符):
惠斯勒Gwen鸟\ N 1997-12-09 \ N
要将文本文件加载
pet.txt
到
pet
表中,请使用以下语句:
MySQL的> LOAD DATA LOCAL INFILE '/path/pet.txt' INTO TABLE pet;
如果您在Windows上使用编辑器创建该文件
\r\n
作为行终止符,则应使用此语句:
MySQL的>LOAD DATA LOCAL INFILE '/path/pet.txt' INTO TABLE pet
LINES TERMINATED BY '\r\n';
(在运行OS X的Apple计算机上,您可能希望使用
LINES TERMINATED BY '\r'
。)
如果需要,可以在
LOAD
DATA
语句中
显式指定列值分隔符和行结束标记
,但默认
值为
制表符和换行符。
这些语句足以使语句
pet.txt
正确
读取文件
。
如果语句失败,则默认情况下您的MySQL安装可能没有启用本地文件功能。 有关 如何更改此信息的信息, 请参见 第6.1.6节“LOAD DATA LOCAL的安全问题” 。
如果要一次添加一条新记录,该
INSERT
语句很有用。
在最简单的形式中,您按照
CREATE
TABLE
语句
中列出的列的顺序为每列提供值
。
假设黛安得到了一只名为
“
Puffball
”
的新仓鼠
。
“
您可以使用如下
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;
+ ---------- + -------- + --------- + ------ + ------------ + ------------ +
| 名字| 老板| 物种| 性别 出生| 死亡|
+ ---------- + -------- + --------- + ------ + ------------ + ------------ +
| 蓬松| 哈罗德| 猫| f | 1993-02-04 | NULL |
| 爪子| 格温| 猫| m | 1994-03-17 | NULL |
| 巴菲| 哈罗德| 狗| f | 1989-05-13 | NULL |
| 方| 班尼| 狗| m | 1990-08-27 | NULL |
| 鲍泽尔| 黛安娜 狗| m | 1979-08-31 | 1995-07-29 |
| Chirpy | 格温| 鸟| f | 1998-09-11 | NULL |
| 惠斯勒| 格温| 鸟| NULL | 1997-12-09 | NULL |
| 苗条| 班尼| 蛇| m | 1996-04-29 | NULL |
| 马勃| 黛安娜 仓鼠| f | 1999-03-30 | NULL |
+ ---------- + -------- + --------- + ------ + ------------ + ------------ +
SELECT
如果要查看整个表格,例如在刚刚加载初始数据集之后,
这种形式
非常有用。
例如,您可能会认为Bowser的出生日期似乎不太合适。
咨询你原来的血统书,你会发现正确的出生年应该是1989年,而不是1979年。
至少有两种方法可以解决这个问题:
如上一节所示,可以轻松检索整个表。
只是省略
声明中
的
WHERE
条款
SELECT
。
但通常你不希望看到整个表格,特别是当它变大时。
相反,您通常对回答特定问题更感兴趣,在这种情况下,您可以对所需信息指定一些约束。
让我们看看他们回答的有关您的宠物的问题的一些选择查询。
您只能从表中选择特定行。 例如,如果您想验证您对Bowser出生日期所做的更改,请选择Bowser的记录,如下所示:
MySQL的> SELECT * FROM pet WHERE name = 'Bowser';
+ -------- + ------- + --------- + ------ + ------------ + - ---------- +
| 名字| 老板| 物种| 性别 出生| 死亡|
+ -------- + ------- + --------- + ------ + ------------ + - ---------- +
| 鲍泽尔| 黛安娜 狗| m | 1989-08-31 | 1995-07-29 |
+ -------- + ------- + --------- + ------ + ------------ + - ---------- +
输出确认年份被正确记录为1989年,而不是1979年。
字符串比较通常不区分大小写,因此您可以将名称指定为
'bowser'
,
'BOWSER'
等等。
查询结果是一样的。
您可以在任何列上指定条件,而不仅仅是
name
。
例如,如果您想知道1998年或之后出生的动物,请测试该
birth
栏:
MySQL的> SELECT * FROM pet WHERE birth >= '1998-1-1';
+ ---------- + ------- + --------- + ------ + ------------ + ------- +
| 名字| 老板| 物种| 性别 出生| 死亡|
+ ---------- + ------- + --------- + ------ + ------------ + ------- +
| Chirpy | 格温| 鸟| f | 1998-09-11 | NULL |
| 马勃| 黛安娜 仓鼠| f | 1999-03-30 | NULL |
+ ---------- + ------- + --------- + ------ + ------------ + ------- +
例如,您可以结合条件来定位雌性狗:
MySQL的> SELECT * FROM pet WHERE species = 'dog' AND sex = 'f';
+ ------- + -------- + --------- + ------ + ------------ + - ----- +
| 名字| 老板| 物种| 性别 出生| 死亡|
+ ------- + -------- + --------- + ------ + ------------ + - ----- +
| 巴菲| 哈罗德| 狗| f | 1989-05-13 | NULL |
+ ------- + -------- + --------- + ------ + ------------ + - ----- +
前面的查询使用
AND
逻辑运算符。
还有一个
OR
运营商:
MySQL的> SELECT * FROM pet WHERE species = 'snake' OR species = 'bird';
+ ---------- + ------- + --------- + ------ + ------------ + ------- +
| 名字| 老板| 物种| 性别 出生| 死亡|
+ ---------- + ------- + --------- + ------ + ------------ + ------- +
| Chirpy | 格温| 鸟| f | 1998-09-11 | NULL |
| 惠斯勒| 格温| 鸟| NULL | 1997-12-09 | NULL |
| 苗条| 班尼| 蛇| 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');
+ ------- + -------- + --------- + ------ + ------------ + - ----- + | 名字| 老板| 物种| 性别 出生| 死亡| + ------- + -------- + --------- + ------ + ------------ + - ----- + | 爪子| 格温| 猫| m | 1994-03-17 | NULL | | 巴菲| 哈罗德| 狗| f | 1989-05-13 | NULL | + ------- + -------- + --------- + ------ + ------------ + - ----- +
如果您不想查看表中的整行,只需将您感兴趣的列命名为逗号分隔。
例如,如果您想知道您的动物何时出生,请选择
name
和
birth
列:
MySQL的> SELECT name, birth FROM pet;
+ ---------- + ------------ +
| 名字| 出生|
+ ---------- + ------------ +
| 蓬松| 1993-02-04 |
| 爪子| 1994-03-17 |
| 巴菲| 1989-05-13 |
| 方| 1990-08-27 |
| 鲍泽尔| 1989-08-31 |
| Chirpy | 1998-09-11 |
| 惠斯勒| 1997-12-09 |
| 苗条| 1996-04-29 |
| 马勃| 1999-03-30 |
+ ---------- + ------------ +
要找出谁拥有宠物,请使用此查询:
MySQL的> SELECT owner FROM pet;
+ -------- +
| 老板|
+ -------- +
| 哈罗德|
| 格温|
| 哈罗德|
| 班尼|
| 黛安娜
| 格温|
| 格温|
| 班尼|
| 黛安娜
+ -------- +
请注意,查询只是
owner
从每条记录中
检索
列,其中一些只出现一次。
要最小化输出,请通过添加关键字检索每个唯一的输出记录一次
DISTINCT
:
MySQL的> SELECT DISTINCT owner FROM pet;
+ -------- +
| 老板|
+ -------- +
| 班尼|
| 黛安娜
| 格温|
| 哈罗德|
+ -------- +
您可以使用
WHERE
子句将行选择与列选择组合在一起。
例如,要仅获取狗和猫的出生日期,请使用以下查询:
MySQL的>SELECT name, species, birth FROM pet
WHERE species = 'dog' OR species = 'cat';
+ -------- + --------- + ------------ + | 名字| 物种| 出生| + -------- + --------- + ------------ + | 蓬松| 猫| 1993-02-04 | | 爪子| 猫| 1994-03-17 | | 巴菲| 狗| 1989-05-13 | | 方| 狗| 1990-08-27 | | 鲍泽尔| 狗| 1989-08-31 | + -------- + --------- + ------------ +
您可能已在前面的示例中注意到结果行没有按特定顺序显示。
当行以某种有意义的方式排序时,通常更容易检查查询输出。
要对结果进行排序,请使用
ORDER
BY
子句。
这是动物的生日,按日期排序:
MySQL的> SELECT name, birth FROM pet ORDER BY birth;
+ ---------- + ------------ +
| 名字| 出生|
+ ---------- + ------------ +
| 巴菲| 1989-05-13 |
| 鲍泽尔| 1989-08-31 |
| 方| 1990-08-27 |
| 蓬松| 1993-02-04 |
| 爪子| 1994-03-17 |
| 苗条| 1996-04-29 |
| 惠斯勒| 1997-12-09 |
| Chirpy | 1998-09-11 |
| 马勃| 1999-03-30 |
+ ---------- + ------------ +
在字符类型列上,排序与所有其他比较操作一样,通常以不区分大小写的方式执行。
这意味着除了它们的情况之外,对于相同的列,订单是未定义的。
您可以使用
BINARY
类似的
方式强制对列进行区分大小写的排序
:
。
ORDER BY BINARY
col_name
默认排序顺序是升序,首先是最小值。
要按反向(降序)排序,请将
DESC
关键字
添加到要排序
的列的名称:
MySQL的> SELECT name, birth FROM pet ORDER BY birth DESC;
+ ---------- + ------------ +
| 名字| 出生|
+ ---------- + ------------ +
| 马勃| 1999-03-30 |
| Chirpy | 1998-09-11 |
| 惠斯勒| 1997-12-09 |
| 苗条| 1996-04-29 |
| 爪子| 1994-03-17 |
| 蓬松| 1993-02-04 |
| 方| 1990-08-27 |
| 鲍泽尔| 1989-08-31 |
| 巴菲| 1989-05-13 |
+ ---------- + ------------ +
您可以对多个列进行排序,并且可以按不同方向对不同列进行排序。 例如,要按动物类型按升序排序,然后按动物类型中的出生日期按降序排序(最年轻的动物首先),请使用以下查询:
MySQL的>SELECT name, species, birth FROM pet
ORDER BY species, birth DESC;
+ ---------- + --------- + ------------ + | 名字| 物种| 出生| + ---------- + --------- + ------------ + | Chirpy | 鸟| 1998-09-11 | | 惠斯勒| 鸟| 1997-12-09 | | 爪子| 猫| 1994-03-17 | | 蓬松| 猫| 1993-02-04 | | 方| 狗| 1990-08-27 | | 鲍泽尔| 狗| 1989-08-31 | | 巴菲| 狗| 1989-05-13 | | 马勃| 仓鼠| 1999-03-30 | | 苗条| 蛇| 1996-04-29 | + ---------- + --------- + ------------ +
该
DESC
关键字仅适用于紧邻其前面的列名(
birth
);
它不会影响
species
列排序顺序。
MySQL提供了几个可用于在日期上执行计算的函数,例如,计算年龄或提取日期的部分。
要确定每只宠物的年龄,请使用此
TIMESTAMPDIFF()
功能。
它的参数是你想要表达结果的单位,以及两个可以取得差异的日期。
以下查询显示了每只宠物的出生日期,当前日期和年龄。
一个
别名
(
age
)是用来制造最终输出列标签更有意义。
MySQL的>SELECT name, birth, CURDATE(),
TIMESTAMPDIFF(YEAR,birth,CURDATE()) AS age
FROM pet;
+ ---------- + ------------ + ------------ + ------ + | 名字| 出生| CURDATE()| 年龄| + ---------- + ------------ + ------------ + ------ + | 蓬松| 1993-02-04 | 2003-08-19 | 10 | | 爪子| 1994-03-17 | 2003-08-19 | 9 | | 巴菲| 1989-05-13 | 2003-08-19 | 14 | | 方| 1990-08-27 | 2003-08-19 | 12 | | 鲍泽尔| 1989-08-31 | 2003-08-19 | 13 | | Chirpy | 1998-09-11 | 2003-08-19 | 4 | | 惠斯勒| 1997-12-09 | 2003-08-19 | 5 | | 苗条| 1996-04-29 | 2003-08-19 | 7 | | 马勃| 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;
+ ---------- + ------------ + ------------ + ------ + | 名字| 出生| CURDATE()| 年龄| + ---------- + ------------ + ------------ + ------ + | 鲍泽尔| 1989-08-31 | 2003-08-19 | 13 | | 巴菲| 1989-05-13 | 2003-08-19 | 14 | | Chirpy | 1998-09-11 | 2003-08-19 | 4 | | 爪子| 1994-03-17 | 2003-08-19 | 9 | | 方| 1990-08-27 | 2003-08-19 | 12 | | 蓬松| 1993-02-04 | 2003-08-19 | 10 | | 马勃| 1999-03-30 | 2003-08-19 | 4 | | 苗条| 1996-04-29 | 2003-08-19 | 7 | | 惠斯勒| 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;
+ ---------- + ------------ + ------------ + ------ + | 名字| 出生| CURDATE()| 年龄| + ---------- + ------------ + ------------ + ------ + | Chirpy | 1998-09-11 | 2003-08-19 | 4 | | 马勃| 1999-03-30 | 2003-08-19 | 4 | | 惠斯勒| 1997-12-09 | 2003-08-19 | 5 | | 苗条| 1996-04-29 | 2003-08-19 | 7 | | 爪子| 1994-03-17 | 2003-08-19 | 9 | | 蓬松| 1993-02-04 | 2003-08-19 | 10 | | 方| 1990-08-27 | 2003-08-19 | 12 | | 鲍泽尔| 1989-08-31 | 2003-08-19 | 13 | | 巴菲| 1989-05-13 | 2003-08-19 | 14 | + ---------- + ------------ + ------------ + ------ +
类似的查询可用于确定死亡动物的死亡年龄。
您可以通过检查
death
值
是否确定这些动物
NULL
。
然后,对于那些具有非
NULL
值的人,计算
death
和
birth
值
之间的差异
:
MySQL的>SELECT name, birth, death,
TIMESTAMPDIFF(YEAR,birth,death) AS age
FROM pet WHERE death IS NOT NULL ORDER BY age;
+ -------- + ------------ + ------------ + ------ + | 名字| 出生| 死亡| 年龄| + -------- + ------------ + ------------ + ------ + | 鲍泽尔| 1989-08-31 | 1995-07-29 | 5 | + -------- + ------------ + ------------ + ------ +
查询使用
death IS NOT NULL
而不是
death <> NULL
因为
NULL
是使用通常的比较运算符无法比较的特殊值。
这将在后面讨论。
请参见
第3.3.4.6节“使用NULL值”
。
如果你想知道哪些动物下个月有生日怎么办?
对于这种类型的计算,年和日是无关紧要的;
您只想提取
birth
列
的月份部分
。
MySQL提供了用于提取日期的部分,如一些功能
YEAR()
,
MONTH()
和
DAYOFMONTH()
。
MONTH()
这是适当的功能。
看看它是如何工作的,运行,显示两者的价值一个简单的查询
birth
和
MONTH(birth)
:
MySQL的> SELECT name, birth, MONTH(birth) FROM pet;
+ ---------- + ------------ + -------------- +
| 名字| 出生| 月(出生)|
+ ---------- + ------------ + -------------- +
| 蓬松| 1993-02-04 | 2 |
| 爪子| 1994-03-17 | 3 |
| 巴菲| 1989-05-13 | 5 |
| 方| 1990-08-27 | 8 |
| 鲍泽尔| 1989-08-31 | 8 |
| Chirpy | 1998-09-11 | 9 |
| 惠斯勒| 1997-12-09 | 12 |
| 苗条| 1996-04-29 | 4 |
| 马勃| 1999-03-30 | 3 |
+ ---------- + ------------ + -------------- +
在接下来的一个月里寻找有生日的动物也很简单。
假设当前月份是4月。
然后是月份值
4
,您可以查找5月(月
5
)
出生的动物,
如下所示:
MySQL的> SELECT name, birth FROM pet WHERE MONTH(birth) = 5;
+ ------- + ------------ +
| 名字| 出生|
+ ------- + ------------ +
| 巴菲| 1989-05-13 |
+ ------- + ------------ +
如果当前月份是12月,则会出现一个小的复杂情况。
你不能只在月份数字(
12
)中
添加一个
并查找月份出生的动物
13
,因为没有这样的月份。
相反,你寻找1月(月
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
)。
如果计算使用无效日期,则计算失败并生成警告:
MySQL的>SELECT '2018-10-31' + INTERVAL 1 DAY;
+ ------------------------------- + | '2018-10-31'+ INTERVAL 1 DAY | + ------------------------------- + | 2018-11-01 | + ------------------------------- + MySQL的>SELECT '2018-10-32' + INTERVAL 1 DAY;
+ ------------------------------- + | '2018-10-32'+ INTERVAL 1 DAY | + ------------------------------- + | NULL | + ------------------------------- + MySQL的>SHOW WARNINGS;
+ --------- + ------ + -------------------------------- -------- + | 等级| 代码| 消息| + --------- + ------ + -------------------------------- -------- + | 警告| 1292 | 日期时间值不正确:'2018-10-32'| + --------- + ------ + -------------------------------- -------- +
在
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 <空| 1> NULL |
+ ---------- + ----------- + ---------- + ---------- +
| NULL | NULL | NULL | NULL |
+ ---------- + ----------- + ---------- + ---------- +
因为任何算术比较的结果
NULL
也是
NULL
,所以你不能从这种比较中获得任何有意义的结果。
在MySQL中,
0
或
NULL
意味着虚假,其他任何意味着真实。
布尔运算的默认真值是
1
。
这种特殊处理
NULL
是为什么在上一节中,有必要确定哪些动物不再使用
death IS NOT
NULL
而不是
death <>
NULL
。
NULL
在a中,
两个
值被视为相等
GROUP BY
。
在执行操作时
ORDER BY
,
NULL
如果您这样做
ORDER BY ... ASC
,则
首先显示值,如果您执行
,则显示最后
值
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 | ''是空的| ''不是空|
+ ----------- + -------- + ------------ + -------- -------- +
| 0 | 1 | 0 | 1 |
+ ----------- + -------- + ------------ + -------- -------- +
因此,完全可以将零或空字符串插入到
NOT NULL
列中,因为这些实际上是这样的
NOT NULL
。
请参见
第B.4.4.3节“NULL值的问题”
。
MySQL提供标准的SQL模式匹配以及基于扩展正则表达式的模式匹配形式,类似于Unix实用程序(如 vi , grep 和 sed) 使用的扩展正则表达式 。
SQL模式匹配使您可以使用
_
匹配任何单个字符并
%
匹配任意数量的字符(包括零个字符)。
在MySQL中,SQL模式默认情况下不区分大小写。
这里显示了一些例子。
不要使用
=
或
<>
使用SQL模式时。
请改用
LIKE
或
NOT LIKE
比较运算符。
要查找以
b
下列
开头的名称
:
MySQL的> SELECT * FROM pet WHERE name LIKE 'b%';
+ -------- + -------- + --------- + ------ + ------------ + - ----------- +
| 名字| 老板| 物种| 性别 出生| 死亡|
+ -------- + -------- + --------- + ------ + ------------ + - ----------- +
| 巴菲| 哈罗德| 狗| f | 1989-05-13 | NULL |
| 鲍泽尔| 黛安娜 狗| m | 1989-08-31 | 1995-07-29 |
+ -------- + -------- + --------- + ------ + ------------ + - ----------- +
要查找以以下结尾的名称
fy
:
MySQL的> SELECT * FROM pet WHERE name LIKE '%fy';
+ -------- + -------- + --------- + ------ + ------------ + - ------ +
| 名字| 老板| 物种| 性别 出生| 死亡|
+ -------- + -------- + --------- + ------ + ------------ + - ------ +
| 蓬松| 哈罗德| 猫| f | 1993-02-04 | NULL |
| 巴菲| 哈罗德| 狗| f | 1989-05-13 | NULL |
+ -------- + -------- + --------- + ------ + ------------ + - ------ +
要查找包含名称
w
:
MySQL的> SELECT * FROM pet WHERE name LIKE '%w%';
+ ---------- + ------- + --------- + ------ + ------------ + ------------ +
| 名字| 老板| 物种| 性别 出生| 死亡|
+ ---------- + ------- + --------- + ------ + ------------ + ------------ +
| 爪子| 格温| 猫| m | 1994-03-17 | NULL |
| 鲍泽尔| 黛安娜 狗| m | 1989-08-31 | 1995-07-29 |
| 惠斯勒| 格温| 鸟| NULL | 1997-12-09 | NULL |
+ ---------- + ------- + --------- + ------ + ------------ + ------------ +
要查找包含五个字符的名称,请使用
_
模式字符的
五个实例
:
MySQL的> SELECT * FROM pet WHERE name LIKE '_____';
+ ------- + -------- + --------- + ------ + ------------ + - ----- +
| 名字| 老板| 物种| 性别 出生| 死亡|
+ ------- + -------- + --------- + ------ + ------------ + - ----- +
| 爪子| 格温| 猫| m | 1994-03-17 | NULL |
| 巴菲| 哈罗德| 狗| f | 1989-05-13 | NULL |
+ ------- + -------- + --------- + ------ + ------------ + - ----- +
MySQL提供的另一种模式匹配使用扩展的正则表达式。
当您测试此类模式的匹配项时,请使用
REGEXP_LIKE()
函数(
REGEXP
或
RLIKE
运算符,它们是同义词
REGEXP_LIKE()
)。
以下列表描述了扩展正则表达式的一些特征:
.
匹配任何单个字符。
字符类
[...]
匹配括号内的任何字符。
例如,
[abc]
匹配
a
,
b
或
c
。
要命名一系列字符,请使用短划线。
[a-z]
匹配任何字母,而
[0-9]
匹配任何数字。
*
匹配前面事物的零个或多个实例。
例如,
x*
匹配任意数量的
x
字符,
[0-9]*
匹配任意数量的数字,并
.*
匹配任意数量的任何数字。
如果模式匹配正在测试的值中的任何位置,则正则表达式模式匹配成功。
(这与
LIKE
模式匹配
不同,
模式匹配仅在模式与整个值匹配时才会成功。)
要锚定模式以使其必须与要测试的值的开头或结尾匹配,请使用模式
^
的开头或
$
结尾。
为了演示扩展正则表达式的工作原理,
LIKE
先前显示
的
查询将在此处重写以供使用
REGEXP_LIKE()
。
要查找
以...开头的名称
b
,请使用
^
以匹配名称的开头:
MySQL的> SELECT * FROM pet WHERE REGEXP_LIKE(name, '^b');
+ -------- + -------- + --------- + ------ + ------------ + - ----------- +
| 名字| 老板| 物种| 性别 出生| 死亡|
+ -------- + -------- + --------- + ------ + ------------ + - ----------- +
| 巴菲| 哈罗德| 狗| f | 1989-05-13 | NULL |
| 鲍泽尔| 黛安娜 狗| m | 1979-08-31 | 1995-07-29 |
+ -------- + -------- + --------- + ------ + ------------ + - ----------- +
要强制将正则表达式比较区分大小写,请使用区分大小写的排序规则,或使用
BINARY
关键字使其中一个字符串成为二进制字符串,或指定
c
匹配控制字符。
这些查询中的每
b
一个在名称的开头
仅匹配小写
:
SELECT * FROM pet WHERE REGEXP_LIKE(name,'^ b'COLLATE utf8mb4_0900_as_cs); SELECT * FROM pet WHERE REGEXP_LIKE(name,BINARY'^ b'); SELECT * FROM pet WHERE REGEXP_LIKE(name,'^ b','c');
要查找以?结尾的名称
fy
,请使用
$
以匹配名称的末尾:
MySQL的> SELECT * FROM pet WHERE REGEXP_LIKE(name, 'fy$');
+ -------- + -------- + --------- + ------ + ------------ + - ------ +
| 名字| 老板| 物种| 性别 出生| 死亡|
+ -------- + -------- + --------- + ------ + ------------ + - ------ +
| 蓬松| 哈罗德| 猫| f | 1993-02-04 | NULL |
| 巴菲| 哈罗德| 狗| f | 1989-05-13 | NULL |
+ -------- + -------- + --------- + ------ + ------------ + - ------ +
要查找包含a的名称
w
,请使用以下查询:
MySQL的> SELECT * FROM pet WHERE REGEXP_LIKE(name, 'w');
+ ---------- + ------- + --------- + ------ + ------------ + ------------ +
| 名字| 老板| 物种| 性别 出生| 死亡|
+ ---------- + ------- + --------- + ------ + ------------ + ------------ +
| 爪子| 格温| 猫| m | 1994-03-17 | NULL |
| 鲍泽尔| 黛安娜 狗| m | 1989-08-31 | 1995-07-29 |
| 惠斯勒| 格温| 鸟| NULL | 1997-12-09 | NULL |
+ ---------- + ------- + --------- + ------ + ------------ + ------------ +
因为正则表达式模式匹配,如果它出现在值的任何位置,则在上一个查询中不必在模式的任何一侧放置通配符以使其与整个值匹配,就像SQL模式一样。
要查找包含五个字符的名称,请使用
^
和
$
匹配名称的开头和结尾,以及
.
中间的
五个实例
:
MySQL的> SELECT * FROM pet WHERE REGEXP_LIKE(name, '^.....$');
+ ------- + -------- + --------- + ------ + ------------ + - ----- +
| 名字| 老板| 物种| 性别 出生| 死亡|
+ ------- + -------- + --------- + ------ + ------------ + - ----- +
| 爪子| 格温| 猫| m | 1994-03-17 | NULL |
| 巴菲| 哈罗德| 狗| f | 1989-05-13 | NULL |
+ ------- + -------- + --------- + ------ + ------------ + - ----- +
您还可以使用
(
“
repeat-
-times
”
)运算符
编写上一个查询
:
{
n
}n
MySQL的> SELECT * FROM pet WHERE REGEXP_LIKE(name, '^.{5}$');
+ ------- + -------- + --------- + ------ + ------------ + - ----- +
| 名字| 老板| 物种| 性别 出生| 死亡|
+ ------- + -------- + --------- + ------ + ------------ + - ----- +
| 爪子| 格温| 猫| m | 1994-03-17 | NULL |
| 巴菲| 哈罗德| 狗| 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;
+ -------- + ---------- +
| 老板| COUNT(*)|
+ -------- + ---------- +
| 班尼| 2 |
| 黛安娜 2 |
| 格温| 3 |
| 哈罗德| 2 |
+ -------- + ---------- +
上述查询用于
GROUP BY
对每个记录进行分组
owner
。
使用的
COUNT()
结合
GROUP BY
是在各种分组表征您的数据非常有用。
以下示例显示了执行动物普查操作的不同方法。
每种动物数量:
MySQL的> SELECT species, COUNT(*) FROM pet GROUP BY species;
+ --------- + ---------- +
| 物种| COUNT(*)|
+ --------- + ---------- +
| 鸟| 2 |
| 猫| 2 |
| 狗| 3 |
| 仓鼠| 1 |
| 蛇| 1 |
+ --------- + ---------- +
每性别的动物数量:
MySQL的> SELECT sex, COUNT(*) FROM pet GROUP BY sex;
+ ------ + ---------- +
| 性别 COUNT(*)|
+ ------ + ---------- +
| NULL | 1 |
| f | 4 |
| m | 4 |
+ ------ + ---------- +
(在此输出中,
NULL
表示性别未知。)
每种物种和性别组合的动物数量:
MySQL的> SELECT species, sex, COUNT(*) FROM pet GROUP BY species, sex;
+ --------- + ------ + ---------- +
| 物种| 性别 COUNT(*)|
+ --------- + ------ + ---------- +
| 鸟| NULL | 1 |
| 鸟| f | 1 |
| 猫| f | 1 |
| 猫| m | 1 |
| 狗| f | 1 |
| 狗| m | 2 |
| 仓鼠| f | 1 |
| 蛇| m | 1 |
+ --------- + ------ + ---------- +
使用时无需检索整个表
COUNT()
。
例如,以前的查询,只在狗和猫上执行时,如下所示:
MySQL的>SELECT species, sex, COUNT(*) FROM pet
WHERE species = 'dog' OR species = 'cat'
GROUP BY species, sex;
+ --------- + ------ + ---------- + | 物种| 性别 COUNT(*)| + --------- + ------ + ---------- + | 猫| f | 1 | | 猫| m | 1 | | 狗| f | 1 | | 狗| m | 2 | + --------- + ------ + ---------- +
或者,如果你想要每性别的动物数量仅适用于已知性别的动物:
MySQL的>SELECT species, sex, COUNT(*) FROM pet
WHERE sex IS NOT NULL
GROUP BY species, sex;
+ --------- + ------ + ---------- + | 物种| 性别 COUNT(*)| + --------- + ------ + ---------- + | 鸟| f | 1 | | 猫| f | 1 | | 猫| m | 1 | | 狗| f | 1 | | 狗| m | 2 | | 仓鼠| f | 1 | | 蛇| m | 1 | + --------- + ------ + ---------- +
如果除了
COUNT()
值
之外还要指定要选择的列
,则
GROUP
BY
应该存在一个用于命名相同列
的
子句。
否则,会发生以下情况:
如果
ONLY_FULL_GROUP_BY
启用
了
SQL模式,则会发生错误:
MySQL的>SET sql_mode = 'ONLY_FULL_GROUP_BY';
查询正常,0行受影响(0.00秒) MySQL的>SELECT owner, COUNT(*) FROM pet;
错误1140(42000):在没有GROUP BY,表达式的聚合查询中 SELECT列表的#1包含非聚合列'menagerie.pet.owner'; 这与sql_mode = only_full_group_by不兼容
如果
ONLY_FULL_GROUP_BY
未启用,则通过将所有行视为单个组来处理查询,但为每个命名列选择的值是不确定的。
服务器可以自由选择任何行中的值:
MySQL的>SET sql_mode = '';
查询正常,0行受影响(0.00秒) MySQL的>SELECT owner, COUNT(*) FROM pet;
+ -------- + ---------- + | 老板| COUNT(*)| + -------- + ---------- + | 哈罗德| 8 | + -------- + ---------- + 1排(0.00秒)
另请参见
第12.20.3节“GROUP BY的MySQL处理”
。
有关
行为和相关优化的
信息
,
请参见
第12.20.1节“聚合(GROUP BY)函数描述”
。
COUNT(
expr
)
该
pet
表记录了您拥有的宠物。
如果您想记录有关它们的其他信息,例如生活中的事件,例如兽医的访问或者出生时,您需要另一张桌子。
这张桌子应该是什么样的?
它需要包含以下信息:
宠物名称,以便您了解每个事件所属的动物。
日期,以便您知道事件发生的时间。
描述事件的字段。
如果您希望能够对事件进行分类,则为事件类型字段。
鉴于这些注意事项,
表
的
CREATE
TABLE
语句
event
可能如下所示:
MySQL的>CREATE TABLE event (name VARCHAR(20), date DATE,
type VARCHAR(15), remark VARCHAR(255));
与
pet
表一样,最简单的方法是通过创建包含以下信息的制表符分隔文本文件来加载初始记录。
名称 | 日期 | 类型 | 备注 |
---|---|---|---|
蓬松 | 1995年5月15日 | 窝 | 4只小猫,3只雌性,1只雄性 |
巴菲 | 1993-06-23 | 窝 | 5只小狗,2只雌性,3只雄性 |
巴菲 | 1994年6月19日 | 窝 | 3只小狗,3只雌性 |
扢 | 1999年3月21日 | 兽医 | 需要喙拉直 |
瘦 | 1997年8月3日 | 兽医 | 断肋骨 |
鲍泽 | 1991年10月12日 | 狗窝 | |
方 | 1991年10月12日 | 狗窝 | |
方 | 1998年8月28日 | 生日 | 给了他一个新的咀嚼玩具 |
爪 | 1998年3月17日 | 生日 | 给了他一个新的跳蚤项圈 |
惠斯勒 | 1998年12月9日 | 生日 | 第一个生日 |
像这样加载记录:
MySQL的> LOAD DATA LOCAL INFILE 'event.txt' INTO TABLE event;
根据您从
pet
表中
运行的查询中学到的内容
,您应该能够对
event
表中
的记录执行检索
;
原则是一样的。
但是,
event
表格本身
何时
不足以回答您可能会问的问题?
假设你想要找出每只宠物的窝的年龄。
我们之前看到过如何计算两个日期的年龄。
母亲的垃圾日期在
event
表格中,但要计算她在该日期的年龄,您需要她的出生日期,该日期存储在
pet
表格中。
这意味着查询需要两个表:
MySQL的>SELECT pet.name,
TIMESTAMPDIFF(YEAR,birth,date) AS age,
remark
FROM pet INNER JOIN event
ON pet.name = event.name
WHERE event.type = 'litter';
+ -------- + ------ + ----------------------------- + | 名字| 年龄| 备注| + -------- + ------ + ----------------------------- + | 蓬松| 2 | 4只小猫,3只雌性,1只雄性| | 巴菲| 4 | 5只小狗,2只雌性,3只雄性| | 巴菲| 5 | 3只小狗,3只雌性| + -------- + ------ + ----------------------------- +
有关此查询的注意事项有以下几点:
该
FROM
子句连接两个表,因为查询需要从两个表中提取信息。
组合(连接)来自多个表的信息时,需要指定一个表中的记录如何与另一个表中的记录匹配。
这很容易,因为它们都有一个
name
列。
该查询使用一个
ON
子句根据值匹配两个表中的记录
name
。
该查询使用a
INNER JOIN
来组合表。
一个
INNER JOIN
或者从表许可证行当且仅当两个表满足所规定的条件,以显示在结果
ON
子句。
在这个例子中,
ON
子句指定
name
列中的
pet
表必须的匹配
name
列
event
表。
如果名称出现在一个表中但不出现在另一个表中,则该行不会出现在结果中,因为该
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 p1.death IS NULL
AND p2.sex = 'm' AND p2.death IS NULL;
+ -------- + ------ + ------- + ------ + --------- + | 名字| 性别 名字| 性别 物种| + -------- + ------ + ------- + ------ + --------- + | 蓬松| f | 爪子| m | 猫| | 巴菲| f | 方| m | 狗| + -------- + ------ + ------- + ------ + --------- +
在此查询中,我们为表名指定别名以引用列,并保持每个列引用与表关联的表的实例。
如果您忘记了数据库或表的名称,或者给定表的结构是什么(例如,它的列被调用),该怎么办? MySQL通过几个语句来解决这个问题,这些语句提供有关它支持的数据库和表的信息。
您之前看到过
SHOW
DATABASES
,它列出了服务器管理的数据库。
要找出当前选择的数据库,请使用以下
DATABASE()
函数:
MySQL的> SELECT DATABASE();
+ ------------ +
| 数据库()|
+ ------------ +
| 动物园|
+ ------------ +
如果您尚未选择任何数据库,则结果为
NULL
。
要找出默认数据库包含的表(例如,当您不确定表的名称时),请使用以下语句:
MySQL的> SHOW TABLES;
+ --------------------- +
| Tables_in_menagerie |
+ --------------------- +
| 事件|
| 宠物|
+ --------------------- +
此语句生成的输出中的列名称始终为
,其中
是数据库的名称。
有关
更多信息
,
请参见
第13.7.6.37节“SHOW TABLES语法”
。
Tables_in_
db_name
db_name
如果要查找表的结构,该
DESCRIBE
语句很有用;
它显示有关每个表列的信息:
MySQL的> DESCRIBE pet;
+ --------- + ------------- + ------ + ------ + --------- + - ----- +
| 领域| 输入| 空| 钥匙| 默认| 额外的|
+ --------- + ------------- + ------ + ------ + --------- + - ----- +
| 名字| varchar(20)| 是的| | NULL | |
| 老板| varchar(20)| 是的| | NULL | |
| 物种| varchar(20)| 是的| | NULL | |
| 性别 char(1)| 是的| | NULL | |
| 出生| 日期| 是的| | NULL | |
| 死亡| 日期| 是的| | NULL | |
+ --------- + ------------- + ------ + ------ + --------- + - ----- +
Field
表示列名称,
Type
是
列
的数据类型,
NULL
指示
列
是否可以包含
NULL
值,
Key
指示列是否已编制索引,并
Default
指定列的默认值。
Extra
显示有关列的特殊信息:如果使用该
AUTO_INCREMENT
选项
创建了列
,则该值将为
auto_increment
空而不是空。
DESC
是一种简短的形式
DESCRIBE
。
有关
更多信息
,
请参见
第13.8.1节“DESCRIBE语法”
。
您可以
CREATE
TABLE
使用该
SHOW
CREATE TABLE
语句
获取
创建现有表所需的
语句。
请参见
第13.7.6.10节“SHOW CREATE TABLE语法”
。
如果表上有索引,则
生成有关它们的信息。
有关此语句的更多信息
,
请参见
第13.7.6.22节“SHOW INDEX语法”
。
SHOW INDEX FROM
tbl_name
在前面的部分中,您以 交互方式 使用 mysql 输入语句并查看结果。 您也可以 在批处理模式下 运行 mysql 。 为此,将要运行的语句放在文件中,然后告诉 mysql 从文件中读取其输入:
外壳> mysql < batch-file
如果您 在Windows下 运行 mysql 并在文件中有一些导致问题的特殊字符,您可以这样做:
C:\> mysql -e "source batch-file
"
如果需要在命令行上指定连接参数,则命令可能如下所示:
shell> 输入密码:mysql -h
host
-uuser
-p <batch-file
********
当您以 这种方式 使用 mysql时 ,您将创建一个脚本文件,然后执行该脚本。
如果您希望脚本继续运行,即使其中的某些语句产生错误,您也应该使用
--force
命令行选项。
为什么要使用脚本? 原因如下:
如果您反复运行查询(例如,每天或每周),使其成为脚本使您可以避免每次执行它时重新输入它。
您可以通过复制和编辑脚本文件从现有的查询生成新查询。
在开发查询时,批处理模式也很有用,特别是对于多行语句或多语句序列。 如果你犯了一个错误,你不必重新输入所有内容。 只需编辑脚本以更正错误,然后告诉 mysql 再次执行它。
如果您有一个产生大量输出的查询,您可以通过寻呼机运行输出,而不是看着它从屏幕顶部滚动:
外壳> mysql < batch-file
| more
您可以捕获文件中的输出以进行进一步处理:
外壳> mysql < batch-file
> mysql.out
您可以将脚本分发给其他人,以便他们也可以运行语句。
某些情况不允许交互式使用,例如,当您从 cron 作业 运行查询时 。 在这种情况下,您必须使用批处理模式。
在批处理模式下
运行
mysql
时,默认输出格式与
交互使用时
的默认输出格式不同(更简洁)
。
例如,
SELECT DISTINCT
species FROM pet
当
mysql
以交互方式运行
时
,输出
看起来像这样
:
+ --------- + | 物种| + --------- + | 鸟| | 猫| | 狗| | 仓鼠| | 蛇| + --------- +
在批处理模式下,输出看起来像这样:
种类 鸟 猫 狗 仓鼠 蛇
如果要以批处理模式获取交互式输出格式,请使用 mysql -t 。 要回显输出执行的语句,请使用 mysql -v 。
您还可以使用
命令或
命令
从
mysql
提示符中
使用脚本
:
source
\.
mysql> mysql>source
filename
;\.
filename
有关 更多信息 , 请参见 第4.5.1.5节“从文本文件执行SQL语句” 。
以下是如何解决MySQL的一些常见问题的示例。
一些示例使用该表
shop
来保存某些交易商(交易商)的每个商品(商品编号)的价格。
假设每个交易者每篇文章只有一个固定价格,则(
article
,
dealer
)是记录的主键。
启动命令行工具 mysql 并选择一个数据库:
外壳> mysql your-database-name
要创建和填充示例表,请使用以下语句:
CREATE TABLE商店( 文章INT UNSIGNED DEFAULT'0000'非空, 经销商CHAR(20)DEFAULT''NOT NULL, 价格DECIMAL(16,2)DEFAULT'0.00'非空, PRIMARY KEY(文章,经销商)); 插入商店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 ORDER BY文章; + --------- + -------- + ------- + | 文章| 经销商| 价格| + --------- + -------- + ------- + | 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 MAX(文章)AS article FROM shop; + --------- + | 文章| + --------- + | 4 | + --------- +
任务:查找最昂贵文章的编号,经销商和价格。
使用子查询可以轻松完成此操作:
SELECT文章,经销商,价格 从商店 价格=(SELECT MAX(价格)FROM shop); + --------- + -------- + ------- + | 文章| 经销商| 价格| + --------- + -------- + ------- + | 0004 | D | 19.95 | + --------- + -------- + ------- +
其他解决方案是使用a
LEFT JOIN
或按价格降序排序所有行,并使用特定于MySQL的
LIMIT
子句
获取第一行
:
SELECT s1.article,s1.dealer,s1.price 从商店s1 LEFT JOIN shop s2 ON s1.price <s2.price WHERE.s2.icle是IS NULL; SELECT文章,经销商,价格 从商店 按订单价格DESC 限制1;
如果有几个最昂贵的文章,每个价格为19.95,
LIMIT
解决方案只会显示其中一个。
任务:找到每篇文章的最高价格。
SELECT文章,MAX(价格)AS价格 从商店 GROUP BY文章 ORDER BY文章; + --------- + ------- + | 文章| 价格| + --------- + ------- + | 0001 | 3.99 | | 0002 | 10.99 | | 0003 | 1.69 | | 0004 | 19.95 | + --------- + ------- +
任务:对于每篇文章,找到价格最贵的经销商或经销商。
这个问题可以通过像这样的子查询来解决:
SELECT文章,经销商,价格 从商店s1 价格=(SELECT MAX(s2.price) 从商店s2 在哪里s1.article = s2.article) ORDER BY文章; + --------- + -------- + ------- + | 文章| 经销商| 价格| + --------- + -------- + ------- + | 0001 | B | 3.99 | | 0002 | A | 10.99 | | 0003 | C | 1.69 | | 0004 | D | 19.95 | + --------- + -------- + ------- +
前面的示例使用相关子查询,这可能是低效的(请参见
第13.2.11.7节“相关子查询”
)。
解决问题的其他可能性是在
FROM
子句中
使用不相关的子查询
,a
LEFT
JOIN
或具有窗口函数的公用表表达式。
不相关的子查询:
SELECT s1.article,dealer,s1.price 从商店s1 加入( SELECT文章,MAX(价格)AS价格 从商店 GROUP BY文章)AS s2 ON s1.article = s2.article AND s1.price = s2.price ORDER BY文章;
LEFT JOIN
:
SELECT s1.article,s1.dealer,s1.price 从商店s1 LEFT JOIN shop s2 ON s1.article = s2.article AND s1.price <s2.price 在哪里s2.article IS NULL ORDER BY s1.article;
的
LEFT JOIN
基础上的作品,当
s1.price
是在其最大价值,不存在
s2.price
具有更大价值,从而相应的
s2.article
值
NULL
。
请参见
第13.2.10.2节“JOIN语法”
。
带窗口函数的公用表表达式:
与s1 AS( 选择文章,经销商,价格, RANK()(文章分区) 按订单价格DESC )AS`排名` 从商店 ) SELECT文章,经销商,价格 从s1 在哪里`Rank` = 1 ORDER BY文章;
您可以使用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;
+ --------- + -------- + ------- + | 文章| 经销商| 价格| + --------- + -------- + ------- + | 0003 | D | 1.25 | | 0004 | D | 19.95 | + --------- + -------- + ------- +
也可以在用户变量中存储数据库对象(如表或列)的名称,然后在SQL语句中使用此变量; 但是,这需要使用准备好的声明。 有关 更多信息 , 请参见 第13.5节“准备好的SQL语句语法” 。
在MySQL中,
InnoDB
表支持检查外键约束。
请参见
第15章,
InnoDB存储引擎
和
第1.8.2.3节“外键差异”
。
仅仅为了连接两个表,不需要外键约束。
对于除以外的存储引擎
InnoDB
,可以在定义列时使用
没有实际效果
的
子句,并且
仅作为备忘录或注释,您当前定义的列旨在引用列中的列。另一张桌子
。
在使用以下语法时要意识到:
REFERENCES
tbl_name
(col_name
)
MySQL不执行任何类型的检查以确保
col_name
实际存在
tbl_name
(或甚至
tbl_name
本身存在)。
MySQL不执行任何类型的操作,
tbl_name
例如删除行以响应对您定义的表中的行所采取的操作;
换句话说,这种语法不会引起任何
行为
ON
DELETE
或
ON UPDATE
行为。
(虽然您可以将
ON
DELETE
or或
ON UPDATE
子句
写为
子句的一部分
REFERENCES
,但也会被忽略。)
此语法创建一个 列 ; 它并 不会 创建任何类型的索引或关键的。
您可以使用如此创建的列作为连接列,如下所示:
CREATE TABLE人( id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, name CHAR(60)NOT NULL, PRIMARY KEY(id) ); CREATE TABLE衬衫( id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, 风格ENUM('t恤','polo','连衣裙')NOT NULL, 颜色ENUM('红色','蓝色','橙色','白色','黑色')NOT NULL, 所有者SMALLINT UNSIGNED NOT NULL参考人(id), PRIMARY KEY(id) ); INSERT INTO VALUES(NULL,'Antonio Paz'); SELECT @last:= LAST_INSERT_ID(); 插入衬衫VALUES (NULL,'polo','blue',@ are), (NULL,'dress','white',@ are), (NULL,'t-shirt','blue',@ pop); INSERT INTO VALUES(NULL,'Lilliana Angelovska'); SELECT @last:= LAST_INSERT_ID(); 插入衬衫VALUES (NULL,'dress','orange',@ are), (NULL,'polo','red',@ are), (NULL,'dress','blue',@ are), (NULL,'t-shirt','white',@ are); SELECT * FROM person; + ---- + --------------------- + | id | 名字| + ---- + --------------------- + | 1 | 安东尼奥帕兹| | 2 | Lilliana Angelovska | + ---- + --------------------- + SELECT * FROM shirt; + ---- + --------- + -------- + ------- + | id | 风格| 颜色| 老板| + ---- + --------- + -------- + ------- + | 1 | polo | 蓝色| 1 | | 2 | 连衣裙| 白色| 1 | | 3 | T恤| 蓝色| 1 | | 4 | 连衣裙| 橙色| 2 | | 5 | polo | 红色| 2 | | 6 | 连衣裙| 蓝色| 2 | | 7 | T恤| 白色| 2 | + ---- + --------- + -------- + ------- + SELECT s。* FROM person p INNER JOIN衬衫s ON s.owner = p.id. 在哪里p.name LIKE'Lilliana%' AND s.color <>'white'; + ---- + ------- + -------- + ------- + | id | 风格| 颜色| 老板| + ---- + ------- + -------- + ------- + | 4 | 连衣裙| 橙色| 2 | | 5 | polo | 红色| 2 | | 6 | 连衣裙| 蓝色| 2 | + ---- + ------- + -------- + ------- +
当以这种方式使用时,
REFERENCES
子句中不显示的输出
SHOW
CREATE TABLE
或
DESCRIBE
:
SHOW CREATE TABLE衬衫\ G *************************** 1。排******************** ******* 表:衬衫 创建表:CREATE TABLE`衬衣`( `id`minintint(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 = utf8mb4
REFERENCES
以这种方式
使用
列定义中
的注释或
“
提醒
”
可以使用
MyISAM
表。
一个
OR
使用单个密钥被很好地优化,因为是的处理
AND
。
一个棘手的案例是搜索两个不同的键结合
OR
:
SELECT field1_index,field2_index FROM test_table WHERE field1_index ='1'或field2_index ='1'
这种情况已经过优化。 请参见 第8.2.1.3节“索引合并优化” 。
您还可以使用
UNION
结合两个单独
SELECT
语句
的输出的
有效方法来解决问题
。
请参见
第13.2.10.3节“UNION语法”
。
每个
SELECT
只搜索一个键,可以进行优化:
SELECT field1_index,field2_index FROM test_table WHERE field1_index ='1' 联盟 SELECT field1_index,field2_index FROM test_table WHERE field2_index ='1';
以下示例显示如何使用位组功能计算用户访问网页的每月天数。
CREATE TABLE t1(年份(4),月份INT UNSIGNED, 当天INT UNSIGNED); 插入t1 VALUES(2000,1,1),(2000,1,20),(2000,1,30),(2000,2,2), (2000,2,23),(2000,2,23);
示例表包含表示用户对页面的访问的年 - 月 - 日值。 要确定这些访问每月发生的天数,请使用以下查询:
选择年,月,BIT_COUNT(BIT_OR(1 <<天))AS天从t1开始 GROUP BY年,月;
哪个回报:
+ ------ + ------- + ------ + | 一年| 月| 天| + ------ + ------- + ------ + | 2000年| 1 | 3 | | 2000年| 2 | 2 | + ------ + ------- + ------ +
该查询计算每个年/月组合在表中显示的天数,并自动删除重复的条目。
该
AUTO_INCREMENT
属性可用于为新行生成唯一标识:
CREATE TABLE动物( id MEDIUMINT NOT NULL AUTO_INCREMENT, name CHAR(30)NOT NULL, PRIMARY KEY(id) ); 插入动物(名称)VALUES ( '狗'),( '猫'),( '企鹅'), ( '松懈'),( '鲸'),( '鸵鸟'); SELECT * FROM animals;
哪个回报:
+ ---- + --------- + | id | 名字| + ---- + --------- + | 1 | 狗| | 2 | 猫| | 3 | 企鹅| | 4 | 松懈| | 5 | 鲸鱼| | 6 | 鸵鸟| + ---- + --------- +
没有为
AUTO_INCREMENT
列
指定值
,因此MySQL会自动分配序列号。
除非
NO_AUTO_VALUE_ON_ZERO
启用
了
SQL模式
,否则您还可以为列显式指定0以生成序列号
。
例如:
INSERT INTO animals(id,name)VALUES(0,'groundhog');
如果声明了列
NOT NULL
,则还可以分配
NULL
给列以生成序列号。
例如:
INSERT INTO animals(id,name)VALUES(NULL,'squirrel');
当您将任何其他值插入
AUTO_INCREMENT
列时,该列将设置为该值并重置序列,以便下一个自动生成的值按顺序从最大列值开始。
例如:
INSERT INTO animals (id,name) VALUES(100,'rabbit');
INSERT INTO animals (id,name) VALUES(NULL,'mouse');
SELECT * FROM animals;
+ ----- + ----------- + | id | 名字| + ----- + ----------- + | 1 | 狗| | 2 | 猫| | 3 | 企鹅| | 4 | 松懈| | 5 | 鲸鱼| | 6 | 鸵鸟| | 7 | 土拨鼠| | 8 | 松鼠| | 100 | 兔子| | 101 | 小鼠| + ----- + ----------- +
更新现有
AUTO_INCREMENT
列值也会重置
AUTO_INCREMENT
序列。
您可以
AUTO_INCREMENT
使用
LAST_INSERT_ID()
SQL函数或者
检索最近自动生成的
值
mysql_insert_id()
C API函数
。
这些函数是特定于连接的,因此它们的返回值不受另一个也执行插入的连接的影响。
对于
AUTO_INCREMENT
足够大
的
列,
请使用最小的整数数据类型,
以保存所需的最大序列值。
当列达到数据类型的上限时,下一次生成序列号的尝试将失败。
UNSIGNED
如果可能,
请使用该
属性以允许更大的范围。
例如,如果你使用
TINYINT
,允许的最大序列号为127的
TINYINT
UNSIGNED
,最大值为255见
第11.2.1节“整型(精确值) - INTEGER,INT,SMALLINT,TINYINT,MEDIUMINT,BIGINT”
为所有整数类型的范围。
对于多行插入,
LAST_INSERT_ID()
而
mysql_insert_id()
实际返回
AUTO_INCREMENT
从钥匙
第一
插入行的。
这使得多行插入可以在复制设置中的其他服务器上正确再现。
要以
AUTO_INCREMENT
1以外
的
值
开头,请
使用
CREATE
TABLE
或
设置该值
ALTER
TABLE
,如下所示:
MySQL的> ALTER TABLE tbl AUTO_INCREMENT = 100;
有关
AUTO_INCREMENT
特定用途的
信息
InnoDB
,请参见
第15.6.1.4节“InnoDB中的AUTO_INCREMENT处理”
。
对于
MyISAM
表,您可以
AUTO_INCREMENT
在多列索引中的辅助列上
指定
。
在这种情况下,
AUTO_INCREMENT
列
的生成值
计算为
。
当您想要将数据放入有序组时,这非常有用。
MAX(
auto_increment_column
)
+ 1 WHERE
prefix=given-prefix
CREATE TABLE动物( grp ENUM('fish','哺乳动物','鸟')NOT NULL, id MEDIUMINT NOT NULL AUTO_INCREMENT, name CHAR(30)NOT NULL, PRIMARY KEY(grp,id) )ENGINE = MyISAM; 插入动物(grp,名称)VALUES ( '哺乳动物', '狗'),( '哺乳动物', '猫'), ( '鸟', '企鹅'),( '鱼', '宽松'),( '哺乳动物', '鲸鱼'), ( '鸟', '鸵鸟'); SELECT * FROM animals ORDER BY grp,id;
哪个回报:
+ -------- + ---- + --------- + | grp | id | 名字| + -------- + ---- + --------- + | 鱼| 1 | 松懈| | 哺乳动物| 1 | 狗| | 哺乳动物| 2 | 猫| | 哺乳动物| 3 | 鲸鱼| | 鸟| 1 | 企鹅| | 鸟| 2 | 鸵鸟| + -------- + ---- + --------- +
在这种情况下(当
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.20节“CREATE TABLE语法”
和
第13.1.9节“ALTER TABLE语法”
。
如何
AUTO_INCREMENT
取决于行为会
NO_AUTO_VALUE_ON_ZERO
SQL模式:
第5.1.11,“SQL服务器模式”
。
如何使用该
LAST_INSERT_ID()
函数查找包含最新
AUTO_INCREMENT
值
的行
:
第12.15节“信息函数”
。
设置
AUTO_INCREMENT
要使用
的
值:
第5.1.8节“服务器系统变量”
。
AUTO_INCREMENT
和复制:
第17.4.1.1节“复制和AUTO_INCREMENT”
。
与
AUTO_INCREMENT
(
auto_increment_increment
和
auto_increment_offset
)
相关的服务器系统变量
,可用于复制:
第5.1.8节“服务器系统变量”
。
有些程序可以让您从MySQL数据库中验证用户身份,还可以将日志文件写入MySQL表。
您可以通过将以下内容添加到Apache配置文件中来更改Apache日志记录格式,以便MySQL可以轻松读取:
LogFormat \ “\”%h \“,%{%Y%m%d%H%M%S} t,%> s,\”%b \“,\”%{Content-Type} o \“,\ \ “%U \”,\ “%{Referer的} I \”,\ “%{用户代理} I \””
要将该格式的日志文件加载到MySQL中,您可以使用如下语句:
LOAD DATA INFILE''INTO/local/access_log
TABLEtbl_name
字段被',''''''''''''''''''''''''''''''''''''''''''
应创建指定的表,以使列与
LogFormat
行写入日志文件的
列相对应
。