3.3.4.7. Pattern Matching
MySQL提供了標(biāo)準(zhǔn)的SQL的pattern匹配和一種基于擴展了的表達(dá)式(類似于Unix中使用的,如vi,grep,sed)的pattern形式。
功能22:SQL pattern匹配允許你使用‘_’ 來匹配任意單個字符, ‘%’來匹配一個任意數(shù)量的字符串(包括0字符串)。 在 MySQL中, SQL patterns 默認(rèn)是大小寫不敏感的。
注意:當(dāng)你使用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’結(jié)尾的名字:
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是使用擴展的常規(guī)表達(dá)式。當(dāng)你測試這用類型的pattern是否匹配時,使用REGEXP和NOT REGEXP操作符(或RLIKE 和NOT RLIKE,他們是同意詞)
一些擴展了的常規(guī)表達(dá)式的字符有:
‘.’ 匹配任意單個字符
一個字符類 ‘[...]’匹配括號內(nèi)的任意字符。如,’[abc]’匹配 ‘a’, ‘b’, or ‘c’。為了命名一系列字符,使用虛線(dash)。‘[a-z]’ 匹配任意字母。而 ‘[0-9]’ 匹配任意數(shù)字
‘*’ 匹配0或更多個其前的事物的實例。如, ‘x*’匹配任意個 ‘x’ 字符。 ‘[0-9]*’匹配任意個數(shù)字?jǐn)?shù)。 matches any ‘.*’ 匹配任意個任何事物。(matches any number of anything.)
如果這個pattern匹配被測試的值中的任意部分的值,一個REGEXP pattern 匹配成功。 (這和LIKE pattern不同,LIKE成功當(dāng)且僅當(dāng)它匹配整個值。)
為了指定一個pattern,以便他可以和被匹配的值的開始和結(jié)尾匹配,要在開頭使用‘^’或在結(jié)尾使用‘$’
為了展示如何使用擴展的常規(guī)表達(dá)式的工作,這里使用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關(guān)鍵字來使一個字符串是二進(jìn)制的字符串。這樣,上述匹配降只匹配名字開頭是小寫’b’的值。
mysql> SELECT * FROM pet WHERE name REGEXP BINARY ‘^b‘;
T查找以‘fy’結(jié)尾的名字,使用‘$’ 來匹配名字的結(jié)尾:
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 |
+----------+-------+---------+------+------------+------------+
因為擴展常規(guī)表達(dá)式匹配成立的條件是字符串中的任意部分匹配就行了。
要查找只包含5個字符的名字,使用‘^’ 和‘$’ 來匹配名字的開頭和結(jié)尾,使用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
數(shù)據(jù)庫有時也用來回答這個問題:“某個類型的數(shù)據(jù)在表中出現(xiàn)的頻率?”。如,你可能想知道你有多少個寵物,或每個主人有幾個寵物,或你想要進(jìn)行各種不同的寵物數(shù)量的調(diào)查
計算你擁有的所有動物的數(shù)量和問題 “表有多少行?”一樣。因為有一個記錄pet. COUNT(*) 計算行數(shù)。所以查詢寵物數(shù)量的語句如下:
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來使記錄按照主人進(jìn)行計算。如果沒有這個關(guān)鍵字,你會得到錯誤的消息:
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 對于按照不同的方式對你的數(shù)據(jù)進(jìn)行分類是很有用的。下面的例子展示了按照不同方式對寵物進(jìn)行數(shù)量查詢。
每個種類的動物數(shù)量:
mysql> SELECT species, COUNT(*) FROM pet GROUP BY species;
+---------+----------+
| species | COUNT(*) |
+---------+----------+
| bird | 2 |
| cat | 2 |
| dog | 3 |
| hamster | 1 |
| snake | 1 |
+---------+----------+
每種性別大的動物數(shù)量:
mysql> SELECT sex, COUNT(*) FROM pet GROUP BY sex;
+------+----------+
| sex | COUNT(*) |
+------+----------+
| NULL | 1 |
| f | 4 |
| m | 4 |
+------+----------+
(NULL 表示性別未知的動物.)
每一個類別和性別結(jié)合的動物數(shù)量:
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 |
+---------+------+----------+
當(dāng)你使用COUNT()時,你不必查詢整個表。如,上述查詢,只是在dogs和cats上執(zhí)行時:
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 |
+---------+------+----------+
或者,你只想知道每個已知性別的動物的數(shù)量:
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表記錄了你有什么寵物。如果你想記錄他們的其他信息,如他們生活中的事件(看病,產(chǎn)仔時間),你需要另外一個表。這個表需要的內(nèi)容有:
包含寵物名字。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.
然后按照上述內(nèi)容,創(chuàng)建一個表:(在建表時,我的date字段按照如下設(shè)置,老是提示出錯。但是把date改成date1,即不是關(guān)鍵字時,就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表單獨不夠用來回答你的問題怎么半?
假設(shè)你想查找具有寵物仔的寵物的年齡。前面講了如何查詢年齡。母親的生產(chǎn)日期在event表中,但是要計算其年齡,需要它的出生日期,這個數(shù)據(jù)在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 |
+--------+------+-----------------------------+
關(guān)于這個查詢有幾點注意事項:
FROM子句有兩個表,因為需要從兩個表中讀取信息。
當(dāng)需要結(jié)合來自多個表的數(shù)據(jù)的時候,你必須指定一個表中的記錄如何和另一個表中的記錄匹配。這個例子中是很簡單的。因為兩個表有同樣的名字列。
因為名字列出現(xiàn)在兩個表中,所以當(dāng)你涉及到列時,你必須指定它的表名。這用通過 表名.列名 來實現(xiàn)。
不需要一定要用兩個不同的表來進(jìn)行連接。如果你想比較一個表中的一個記錄和另外一個記錄,那么一個表自身也可以和它自己連接。如,要查找寵物中的一對寵物,你可以pet表和它自身連接來產(chǎn)生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 |
+--------+------+--------+------+---------+
這個查詢中,指定了一個表的別名用來引用列并保證各個列的聯(lián)系。