MySQL提供了标准的SQL的pattern匹配和一种基于扩展了的表达式(类似于Unix中使用的,如vi,grep,sed)的pattern形式。
功能22:SQL pattern匹配允许你使用‘_’ 来匹配任意单个字符, ‘%’来匹配一个任意数量的字符串(包括0字符串)。 在 MySQL中, SQL patterns 默认是大小写不敏感的。
注意:当你使用SQL pattern时,不能使用= or <>; 而是使用 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个字符的名字,要使用5个 ‘_’ pattern 符:
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提供的另外一种patter是使用扩展的常规表达式。当你测试这用类型的pattern是否匹配时,使用REGEXP和NOT REGEXP操作符(或RLIKE 和NOT RLIKE,他们是同意词)
一些扩展了的常规表达式的字符有:
- ‘.’ 匹配任意单个字符
- 一个字符类 ‘[...]’匹配括号内的任意字符。如,’[abc]’匹配 ‘a’, ‘b’, or ‘c’。为了命名一系列字符,使用虚线(dash)。‘[a-z]’ 匹配任意字母。而 ‘[0-9]’ 匹配任意数字
- ‘*’ 匹配0或更多个其前的事物的实例。如, ‘x*’匹配任意个 ‘x’ 字符。 ‘[0-9]*’匹配任意个数字数。 matches any ‘.*’ 匹配任意个任何事物。(matches any number of anything.)
- 如果这个pattern匹配被测试的值中的任意部分的值,一个REGEXP pattern 匹配成功。 (这和LIKE pattern不同,LIKE成功当且仅当它匹配整个值。)
- 为了指定一个pattern,以便他可以和被匹配的值的开始和结尾匹配,要在开头使用‘^’或在结尾使用‘$’
- 为了展示如何使用扩展的常规表达式的工作,这里使用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 |
+--------+--------+---------+------+------------+------------+
在MySQL 5.0中,如果你想强制的使REGEXP比较大小写敏感,使用BINARY关键字来使一个字符串是二进制的字符串。这样,上述匹配降只匹配名字开头是小写’b’的值。
mysql> SELECT * FROM pet WHERE name REGEXP BINARY ‘^b‘;
T查找以‘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 |
+----------+-------+---------+------+------------+------------+
因为扩展常规表达式匹配成立的条件是字符串中的任意部分匹配就行了。
要查找只包含5个字符的名字,使用‘^’ 和‘$’ 来匹配名字的开头和结尾,使用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} (“repeat-n-times”)来写上个语句的查询:
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 |
+-------+--------+---------+------+------------+-------+
3.3.4.8. Counting Rows
数据库有时也用来回答这个问题:“某个类型的数据在表中出现的频率?”。如,你可能想知道你有多少个宠物,或每个主人有几个宠物,或你想要进行各种不同的宠物数量的调查
计算你拥有的所有动物的数量和问题 “表有多少行?”一样。因为有一个记录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来使记录按照主人进行计算。如果没有这个关键字,你会得到错误的消息:
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
COUNT() 和 GROUP BY 对于按照不同的方式对你的数据进行分类是很有用的。下面的例子展示了按照不同方式对宠物进行数量查询。
每个种类的动物数量:
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()时,你不必查询整个表。如,上述查询,只是在dogs和cats上执行时:
mysql> SELECT species, sex, COUNT(*) FROM pet
-> WHERE species = ‘dog‘ OR species = ‘cat‘
-> GROUP BY species, sex;
+---------+------+----------+
| species | sex | COUNT(*) |
+---------+------+----------+
| cat | f | 1 |
| cat | m | 1 |
| dog | f | 1 |
| dog | m | 2 |
+---------+------+----------+
或者,你只想知道每个已知性别的动物的数量:
mysql> SELECT species, sex, COUNT(*) FROM pet
-> WHERE sex IS NOT NULL
-> GROUP BY species, sex;
+---------+------+----------+
| species | sex | COUNT(*) |
+---------+------+----------+
| bird | f | 1 |
| cat | f | 1 |
| cat | m | 1 |
| dog | f | 1 |
| dog | m | 2 |
| hamster | f | 1 |
| snake | m | 1 |
+---------+------+----------+
3.3.4.9. Using More Than one Table
Pet表记录了你有什么宠物。如果你想记录他们的其他信息,如他们生活中的事件(看病,产仔时间),你需要另外一个表。这个表需要的内容有:
- 包含宠物名字。To contain the pet name so that you know which animal each event pertains to.
- 事件的日期A date so that you know when the event occurred.
- 描述事件的字段。A field to describe the event.
- 时间类型。An event type field, if you want to be able to categorize events.
然后按照上述内容,创建一个表:(在建表时,我的date字段按照如下设置,老是提示出错。但是把date改成date1,即不是关键字时,就OK了。估计是因为date和后面的类型名DATE一样的缘故)
mysql> CREATE TABLE event (name VARCHAR(20), date DATE,
-> type VARCHAR(15), remark VARCHAR(255));
表的信息如下 。可以使用文本建立。As with the pet table, it‘s easiest to load the initial records by creating a tab-delimited text file containing the information:
name
|
date
|
type
|
remark
|
Fluffy
|
1995-05-15
|
litter
|
4 kittens, 3 female, 1 male
|
Buffy
|
1993-06-23
|
litter
|
5 puppies, 2 female, 3 male
|
Buffy
|
1994-06-19
|
litter
|
3 puppies, 3 female
|
Chirpy
|
1999-03-21
|
vet
|
needed beak straightened
|
Slim
|
1997-08-03
|
vet
|
broken rib
|
Bowser
|
1991-10-12
|
kennel
|
|
Fang
|
1991-10-12
|
kennel
|
|
Fang
|
1998-08-28
|
birthday
|
Gave him a new chew toy
|
Claws
|
1998-03-17
|
birthday
|
Gave him a new flea collar
|
Whistler
|
1998-12-09
|
birthday
|
First birthday
|
装入文件如下:
mysql> LOAD DATA LOCAL INFILE ‘event.txt‘ INTO TABLE event;
使用上述知识你可以访问event表了。但是,event表单独不够用来回答你的问题怎么半?
假设你想查找具有宠物仔的宠物的年龄。前面讲了如何查询年龄。母亲的生产日期在event表中,但是要计算其年龄,需要它的出生日期,这个数据在pet表中。这就意味着要查询两个表:
mysql> SELECT pet.name,
-> (YEAR(date)-YEAR(birth)) - (RIGHT(date,5)<RIGHT(birth,5)) AS age,
-> remark
-> FROM pet, event
-> WHERE pet.name = event.name AND event.type = ‘litter‘;
+--------+------+-----------------------------+
| name | age | remark |
+--------+------+-----------------------------+
| Fluffy | 2 | 4 kittens, 3 female, 1 male |
| Buffy | 4 | 5 puppies, 2 female, 3 male |
| Buffy | 5 | 3 puppies, 3 female |
+--------+------+-----------------------------+
关于这个查询有几点注意事项:
- FROM子句有两个表,因为需要从两个表中读取信息。
- 当需要结合来自多个表的数据的时候,你必须指定一个表中的记录如何和另一个表中的记录匹配。这个例子中是很简单的。因为两个表有同样的名字列。
- 因为名字列出现在两个表中,所以当你涉及到列时,你必须指定它的表名。这用通过 表名.列名 来实现。
不需要一定要用两个不同的表来进行连接。如果你想比较一个表中的一个记录和另外一个记录,那么一个表自身也可以和它自己连接。如,要查找宠物中的一对宠物,你可以pet表和它自身连接来产生female和male的对。
mysql> SELECT p1.name, p1.sex, p2.name, p2.sex, p1.species
-> FROM pet AS p1, pet AS p2
-> WHERE p1.species = p2.species AND p1.sex = ‘f‘ AND p2.sex = ‘m‘;
+--------+------+--------+------+---------+
| name | sex | name | sex | species |
+--------+------+--------+------+---------+
| Fluffy | f | Claws | m | cat |
| Buffy | f | Fang | m | dog |
| Buffy | f | Bowser | m | dog |
+--------+------+--------+------+---------+
这个查询中,指定了一个表的别名用来引用列并保证各个列的联系。