正则表达式:匹配文本,将一个模式(正则表达式)与一个文本串进行比较。
MySQL 仅支持多数正则表达式实现的一个很小的子集。MySQL使用WHERE子句对正则表达式提供了初步的支持,允许你通过指定正则表达式来过滤SELECT检索出来的数据。
检索列prod_name包含文本1000的所有行
mysql> SELECT * FROM products WHERE prod_name REGEXP '1000';
+---------+---------+--------------+------------+---------------------------------------+
| prod_id | vend_id | prod_name | prod_price | prod_desc |
+---------+---------+--------------+------------+---------------------------------------+
| JP1000 | 1005 | JetPack 1000 | 35.00 | JetPack 1000, intended for single use |
+---------+---------+--------------+------------+---------------------------------------+
1 row in set (0.08 sec)
这条语句和过去我们使用LIKE很相似,但是使用LIKE的结果却为空,从这也看出正则表达式匹配和使用LIKE匹配的差别。
mysql> SELECT * FROM products WHERE prod_name LIKE '1000';
Empty set (0.00 sec)
LIKE:匹配整个列,如果被匹配的文本在列值中出现,LIKE将不会找到它,相应的行也不会被返回。(除非使用通配符)
REGEXP:在列值中匹配,如果被匹配的文本在列值中出现,REGEXP将会找到它,相应的行将被返回。当然REGEXP也可以用来匹配整个列值,使用后面介绍的^
和$
定位符。
MySQL正则表达式匹配不区分大小写,为了使其区分大小写,可以使用REGEXP BINARY。
mysql> SELECT * FROM products WHERE prod_name REGEXP '.000';
+---------+---------+--------------+------------+---------------------------------------+
| prod_id | vend_id | prod_name | prod_price | prod_desc |
+---------+---------+--------------+------------+---------------------------------------+
| JP1000 | 1005 | JetPack 1000 | 35.00 | JetPack 1000, intended for single use |
| JP2000 | 1005 | JetPack 2000 | 55.00 | JetPack 2000, multi-use |
+---------+---------+--------------+------------+---------------------------------------+
2 rows in set (0.00 sec)
.
是正则表达式中的一个特殊字符,它表示匹配任一一个字符。
为了检索两个串之一,使用|
mysql> SELECT * FROM products WHERE prod_name REGEXP '1000 | 2000';
+---------+---------+--------------+------------+-------------------------+
| prod_id | vend_id | prod_name | prod_price | prod_desc |
+---------+---------+--------------+------------+-------------------------+
| JP2000 | 1005 | JetPack 2000 | 55.00 | JetPack 2000, multi-use |
+---------+---------+--------------+------------+-------------------------+
1 row in set (0.00 sec)
mysql> SELECT * FROM products WHERE prod_name REGEXP '1000|2000';
+---------+---------+--------------+------------+---------------------------------------+
| prod_id | vend_id | prod_name | prod_price | prod_desc |
+---------+---------+--------------+------------+---------------------------------------+
| JP1000 | 1005 | JetPack 1000 | 35.00 | JetPack 1000, intended for single use |
| JP2000 | 1005 | JetPack 2000 | 55.00 | JetPack 2000, multi-use |
+---------+---------+--------------+------------+---------------------------------------+
2 rows in set (0.00 sec)
|
为正则表达式中OR操作符
注意:1000 | 2000
:匹配的是1000空格
和 空格20000
mysql> SELECT * FROM products WHERE prod_name REGEXP '[123] Ton';
+---------+---------+-------------+------------+----------------------------------------------------------------+
| prod_id | vend_id | prod_name | prod_price | prod_desc |
+---------+---------+-------------+------------+----------------------------------------------------------------+
| ANV02 | 1001 | 1 ton anvil | 9.99 | 1 ton anvil, black, complete with handy hook and carrying case |
| ANV03 | 1001 | 2 ton anvil | 14.99 | 2 ton anvil, black, complete with handy hook and carrying case |
+---------+---------+-------------+------------+----------------------------------------------------------------+
2 rows in set (0.00 sec)
[123]定义一组字符,它的意思是匹配1或2或3。
[123] Ton等价于:[1|2|3] Ton
[^123]:匹配除这些字符外的任何东西
mysql> SELECT * FROM products WHERE prod_name REGEXP '[1-5] Ton';
+---------+---------+--------------+------------+----------------------------------------------------------------+
| prod_id | vend_id | prod_name | prod_price | prod_desc |
+---------+---------+--------------+------------+----------------------------------------------------------------+
| ANV01 | 1001 | .5 ton anvil | 5.99 | .5 ton anvil, black, complete with handy hook |
| ANV02 | 1001 | 1 ton anvil | 9.99 | 1 ton anvil, black, complete with handy hook and carrying case |
| ANV03 | 1001 | 2 ton anvil | 14.99 | 2 ton anvil, black, complete with handy hook and carrying case |
+---------+---------+--------------+------------+----------------------------------------------------------------+
3 rows in set (0.00 sec)
[1-5] Ton
:等价于[12345] Ton
也就是去匹配正则表达式中的特殊字符。使用\\
转译
如查找.
则需要REGEXP ‘\.’
类 | 说明 |
---|---|
[:alnum:] | 任意字母和数字(同[a-zA-Z0-9]) |
[:alpha:] | 任意字符(同[a-zA-Z]) |
[:blank:] | 空格和制表(同[\t]) |
[:digit:] | 任意数字(同[0-9]) |
类 | 说明 |
---|---|
* | 0个或多个匹配 |
+ | 1个或多个匹配 |
? | 0个或1个匹配 |
{n} | n个匹配 |
{n,} | >=n个匹配 |
{n,m} | >=n <= m个匹配 |
mysql> SELECT * FROM products WHERE prod_name REGEXP '\\([0-9] sticks?\\)';
+---------+---------+----------------+------------+-----------------------------+
| prod_id | vend_id | prod_name | prod_price | prod_desc |
+---------+---------+----------------+------------+-----------------------------+
| TNT1 | 1003 | TNT (1 stick) | 2.50 | TNT, red, single stick |
| TNT2 | 1003 | TNT (5 sticks) | 10.00 | TNT, red, pack of 10 sticks |
+---------+---------+----------------+------------+-----------------------------+
2 rows in set (0.00 sec)
mysql> SELECT * FROM products WHERE prod_name REGEXP '[[:digit:]]{4}';
+---------+---------+--------------+------------+---------------------------------------+
| prod_id | vend_id | prod_name | prod_price | prod_desc |
+---------+---------+--------------+------------+---------------------------------------+
| JP1000 | 1005 | JetPack 1000 | 35.00 | JetPack 1000, intended for single use |
| JP2000 | 1005 | JetPack 2000 | 55.00 | JetPack 2000, multi-use |
+---------+---------+--------------+------------+---------------------------------------+
2 rows in set (0.00 sec)
类 | 说明 |
---|---|
^ | 文本多的开始 |
$ | 文本的结尾 |
[[:<:]] | 词的开始 |
[[:>:]] | 词的结尾 |
mysql> SELECT * FROM products WHERE prod_name REGEXP '^[0-9\\.]';
+---------+---------+--------------+------------+----------------------------------------------------------------+
| prod_id | vend_id | prod_name | prod_price | prod_desc |
+---------+---------+--------------+------------+----------------------------------------------------------------+
| ANV01 | 1001 | .5 ton anvil | 5.99 | .5 ton anvil, black, complete with handy hook |
| ANV02 | 1001 | 1 ton anvil | 9.99 | 1 ton anvil, black, complete with handy hook and carrying case |
| ANV03 | 1001 | 2 ton anvil | 14.99 | 2 ton anvil, black, complete with handy hook and carrying case |
+---------+---------+--------------+------------+----------------------------------------------------------------+
3 rows in set (0.00 sec)
以上查询以数字或者小数点开始的数据。
可以使用带文本串的REGEXP来测试表达式
例如:SELECT 'hello' REGEXP '[0-9]';
匹配返回1,不匹配返回0。
计算字段不是实际存在于数据库表中的,而是通过在运行时在SELECT语句创建的。
拼接字段:将值联结到一起构成单个值。
mysql> SELECT Concat(vend_name, ' (', vend_country, ')') FROM vendors ORDER BY vend_name;
+--------------------------------------------+
| Concat(vend_name, ' (', vend_country, ')') |
+--------------------------------------------+
| ACME (USA) |
| Anvils R Us (USA) |
| Furball Inc. (USA) |
| Jet Set (England) |
| Jouets Et Ours (France) |
| LT Supplies (USA) |
+--------------------------------------------+
6 rows in set (0.00 sec)
上述输出的列是没有名字的,要想在客户机应用如(MyBatis)中引用,需要设置别名。
mysql> SELECT Concat(vend_name, ' (', vend_country, ')') AS vend_title FROM vendors ORDER BY vend_name;
+-------------------------+
| vend_title |
+-------------------------+
| ACME (USA) |
| Anvils R Us (USA) |
| Furball Inc. (USA) |
| Jet Set (England) |
| Jouets Et Ours (France) |
| LT Supplies (USA) |
+-------------------------+
6 rows in set (0.00 sec)
执行算术计算
mysql> SELECT prod_id, quantity, item_price FROM orderitems WHERE order_num = 20005;
+---------+----------+------------+
| prod_id | quantity | item_price |
+---------+----------+------------+
| ANV01 | 10 | 5.99 |
| ANV02 | 3 | 9.99 |
| TNT2 | 5 | 10.00 |
| FB | 1 | 10.00 |
+---------+----------+------------+
4 rows in set (0.06 sec)
mysql> SELECT prod_id, quantity, item_price, item_price * quantity AS expanded_price FROM orderitems WHERE order_num = 20005;
+---------+----------+------------+----------------+
| prod_id | quantity | item_price | expanded_price |
+---------+----------+------------+----------------+
| ANV01 | 10 | 5.99 | 59.90 |
| ANV02 | 3 | 9.99 | 29.97 |
| TNT2 | 5 | 10.00 | 50.00 |
| FB | 1 | 10.00 | 10.00 |
+---------+----------+------------+----------------+
4 rows in set (0.00 sec)
函数没有SQL的可移植性强,所以在使用时应该保证做好代码注释。
函数 | 说明 |
---|---|
Left() | 返回串左边的字符 |
Length() | 返回串的长度 |
Locate() | 找出串的一个子串 |
Lower() | 将串转换为小写 |
LTrim() | 去掉串左边的空格 |
Right() | 返回串右边的字符 |
RTrim() | 去掉串右边的空格 |
Soundex() | 返回串的SOUNDEX值 |
SubString() | 返回子串的字符 |
Upper() | 将串转换为大写 |
使用:
SELECT prod_id, Left(prod_id, 2) FROM products;
SELECT prod_id, Right(prod_id, 2) FROM products;
SELECT Length(prod_id) FROM products;
SELECT prod_name, Lower(prod_name), Upper(prod_name) FROM products;
SELECT prod_name, SubString(prod_name, 1, 2) FROM products;
SELECT LOCATE('ton', prod_name) FROM products;
函数 | 说明 |
---|---|
AddDate() | 增加一个日期(天、周等) |
AddTime() | 增加一个时间(时、分等) |
CurDate() | 返回当前日期 |
CurTime() | 返回当前时间 |
Date() | 返回日期时间的日期部分 |
DateDiff() | 计算两个日期之差 |
Date_Add() | 高度灵活的日期运算函数 |
Date_Format() | 返回一个格式化的日期或时间串 |
Day() | 返回一个日期的天数部分 |
DayOfWeek() | 对于一个日期,返回对应的星期几 |
Hour() | 返回一个时间的小时部分 |
Minute() | 返回一个时间的分钟部分 |
Month() | 返回一个日期的月份部分 |
Now() | 返回当前日期和时间 |
Second() | 返回一个时间的秒部分 |
Time() | 返回一个日期时间的时间部分 |
Year() | 返回一个日期的年份部分 |
mysql> SELECT now(), Date(now()), Time(now());
+---------------------+-------------+-------------+
| now() | Date(now()) | Time(now()) |
+---------------------+-------------+-------------+
| 2017-07-09 12:41:39 | 2017-07-09 | 12:41:39 |
+---------------------+-------------+-------------+
1 row in set (0.01 sec)
日期的格式为:yyyy-mm-dd,如2017-07-09。这是首选的日期根式。
MySQL中datetime类型存储日期及时间。可以使用Date()函数提取需要的日期。
mysql> SELECT * FROM orders WHERE Date(order_date) = '2005-09-01';
+-----------+---------------------+---------+
| order_num | order_date | cust_id |
+-----------+---------------------+---------+
| 20005 | 2005-09-01 00:00:00 | 10001 |
+-----------+---------------------+---------+
1 row in set (0.00 sec)
如何检索出形如2005年9月份的所有订单?
mysql> SELECT * FROM orders WHERE Date(order_date) BETWEEN '2005-09-01' AND '2005-09-30';
+-----------+---------------------+---------+
| order_num | order_date | cust_id |
+-----------+---------------------+---------+
| 20005 | 2005-09-01 00:00:00 | 10001 |
| 20006 | 2005-09-12 00:00:00 | 10003 |
| 20007 | 2005-09-30 00:00:00 | 10004 |
+-----------+---------------------+---------+
3 rows in set (0.00 sec)
但是以上方法需要写出每个月份有多少天,以及需要关心闰年。
mysql> SELECT * FROM orders WHERE Year(order_date) = 2005 AND Month(order_date) = 9;
+-----------+---------------------+---------+
| order_num | order_date | cust_id |
+-----------+---------------------+---------+
| 20005 | 2005-09-01 00:00:00 | 10001 |
| 20006 | 2005-09-12 00:00:00 | 10003 |
| 20007 | 2005-09-30 00:00:00 | 10004 |
+-----------+---------------------+---------+
3 rows in set (0.00 sec)
数值处理函数仅处理数值数据。
函数 | 说明 |
---|---|
Abs() | 返回一个数的绝对值 |
Cos() | 返回一个角度的余弦 |
Exp() | 返回一个数的指数值 |
Mod() | 返回除操作的余数 |
Pi() | 返回圆周率 |
Rand() | 返回一个随机数 |
Sin() | 返回一个角度的正弦 |
Sqrt() | 返回一个数的平方根 |
Tan() | 返回一个角度的正切 |
我们经常需要汇总数据而不是把数据实际检索出来,为此MySQL提供了聚集函数。
以上都是聚集函数的使用场合。
聚集函数:运行在行组上,计算和返回单个值的函数。
函数 | 说明 |
---|---|
AVG() | 返回某列的平均值 |
COUNT() | 返回某列的行数 |
MAX() | 返回某列的最大值 |
MIN() | 返回某列的最小值 |
SUM() | 返回某列子和 |
通过对表中行数计数并计算特定列值之和,求得该列的平均值。
返回所有列的平均值:
mysql> SELECT AVG(prod_price) AS avg_price FROM products;
+-----------+
| avg_price |
+-----------+
| 16.133571 |
+-----------+
1 row in set (0.00 sec)
返回特定列或行的平均值:
mysql> SELECT AVG(prod_price) AS avg_price FROM products WHERE vend_id = 1003;
+-----------+
| avg_price |
+-----------+
| 13.212857 |
+-----------+
1 row in set (0.06 sec)
AVG()函数只能用来确定特定数值列的平均值,而且列名必须作为函数参数给出。为了获得多个列的平均值,必须使用多个AVG()函数。
AVG()函数忽略列值为NULL的行。
COUNT()函数用来计数。可以利用COUNT()确定表中行的数目或符合特定条件的行的数目。
COUNT()函数的两种使用方式:
返回customer表中客户的总数:
mysql> SELECT COUNT(*) AS num_cust FROM customers;
+----------+
| num_cust |
+----------+
| 5 |
+----------+
1 row in set (0.07 sec)
返回具有电子邮件地址的客户计数:
mysql> SELECT COUNT(cust_email) AS num_cust FROM customers;
+----------+
| num_cust |
+----------+
| 3 |
+----------+
1 row in set (0.00 sec)
mysql> SELECT * FROM customers;
+---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+
| cust_id | cust_name | cust_address | cust_city | cust_state | cust_zip | cust_country | cust_contact | cust_email |
+---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+
| 10001 | Coyote Inc. | 200 Maple Lane | Detroit | MI | 44444 | USA | Y Lee | [email protected] |
| 10002 | Mouse House | 333 Fromage Lane | Columbus | OH | 43333 | USA | Jerry Mouse | NULL |
| 10003 | Wascals | 1 Sunny Place | Muncie | IN | 42222 | USA | Jim Jones | [email protected] |
| 10004 | Yosemite Place | 829 Riverside Drive | Phoenix | AZ | 88888 | USA | Y Sam | [email protected] |
| 10005 | E Fudd | 4545 53rd Street | Chicago | IL | 54545 | USA | E Fudd | NULL |
+---------+----------------+---------------------+-----------+------------+----------+--------------+--------------+---------------------+
5 rows in set (0.00 sec)
NULL值:如果指定列名,则指定列的值为空的行被COUNT()函数忽略,但如果COUNT()函数中使用的是星号(*),则不忽略。
返回指定列中的最大值。必须指定列名。
mysql> SELECT MAX(prod_price) AS max_price FROM products;
+-----------+
| max_price |
+-----------+
| 55.00 |
+-----------+
1 row in set (0.04 sec)
等价于:
mysql> SELECT prod_price AS 'max(prod_price)' FROM products ORDER BY prod_price DESC LIMIT 1;
+-----------------+
| max(prod_price) |
+-----------------+
| 55.00 |
+-----------------+
1 row in set (0.00 sec)
返回指定列的最小值。必须指定列名。
mysql> SELECT MIN(prod_price) AS max_price FROM products;
+-----------+
| max_price |
+-----------+
| 2.50 |
+-----------+
1 row in set (0.00 sec)
MAX()与MIN()函数都忽略列值为NULL的行。两个函数对非数值数据也适用。
返回指定列值的和。
mysql> SELECT SUM(quantity) AS items_ordered FROM orderitems WHERE order_num = 20005;
+---------------+
| items_ordered |
+---------------+
| 19 |
+---------------+
1 row in set (0.00 sec)
SUM()函数也可以用来合计计算值。
mysql> SELECT SUM(item_price * quantity) AS total_price FROM orderitems WHERE order_num = 20005;
+-------------+
| total_price |
+-------------+
| 149.87 |
+-------------+
1 row in set (0.00 sec)
SUM()函数忽略列值为NULL的行。
针对MySQL 5及后期版本
只包含不同的值,指定DISTINCT参数。
mysql> SELECT AVG(DISTINCT prod_price) AS avg_price FROM products WHERE vend_id = 1003;
+-----------+
| avg_price |
+-----------+
| 15.998000 |
+-----------+
1 row in set (0.05 sec)
mysql> SELECT COUNT(*) AS num_items,
-> MIN(prod_price) AS price_min,
-> MAX(prod_price) AS price_max,
-> AVG(prod_price) AS price_avg
-> FROM products;
+-----------+-----------+-----------+-----------+
| num_items | price_min | price_max | price_avg |
+-----------+-----------+-----------+-----------+
| 14 | 2.50 | 55.00 | 16.133571 |
+-----------+-----------+-----------+-----------+
1 row in set (0.00 sec)
子查询:嵌套在其他查询中的查询。
查询订购物品TNT2的所有客户
步骤:
- 检索包含物品TNT2
的所有订单的编号。
SELECT order_num FROM orderitems WHERE prod_id = 'TNT2';
SELECT cust_id FROM orders WHERE order_num IN (20005, 20007);
SELECT * FROM customers WHERE cust_id IN (10001, 10004);
使用子查询就是把上述三个查询合成一条语句。
SELECT *
FROM customers
WHERE cust_id IN (SELECT cust_id
FROM orders
WHERE order_num IN (SELECT order_num
FROM orderitems
WHERE prod_id = 'TNT2'));
在SELECT语句中,子查询总是从内向外处理。
步骤:
从customers表中检索客户列表。
对于检索出来的每个客户,统计其在orders表中的订单数目。
SELECT
cust_id,
cust_name,
(SELECT count(*)
FROM orders
WHERE cust_id = customers.cust_id)
AS orders
FROM
customers;