17章 組合查詢
UNION
操作符將多條SELECT
語句組合
17.1 組合查詢
SELECT
語句查詢,結果作爲單條查詢返回。稱爲並(union)或者複合查詢(compound query)。
可能需要的地方:
- 單個查詢中從不同表返回類似結構的數據。
- 單表執行多次查詢,按單個查詢返回。
注意:多數情況下,組合相同的表的兩個查詢工作,與具有多個SELECT
子句條件的單條查詢相同。
17.2 創建組合查詢
UNION
來組合SQL查詢。
17.2.1 UNION
使用
- 在每條
SELECT
語句之間放入UNION
語句。
例如,需要查詢價格小於5的列表,和供應商1001、1002的所有物品。
1.使用多條SELECT
方式
mysql> SELECT vend_id, prod_id, prod_price FROM products WHERE prod_price <= 5;
+---------+---------+------------+
| vend_id | prod_id | prod_price |
+---------+---------+------------+
| 1003 | FC | 2.50 |
| 1002 | FU1 | 3.42 |
| 1003 | SLING | 4.49 |
| 1003 | TNT1 | 2.50 |
+---------+---------+------------+
mysql> SELECT vend_id,prod_id, prod_price FROM products WHERE vend_id IN (1001, 1002);
+---------+---------+------------+
| vend_id | prod_id | prod_price |
+---------+---------+------------+
| 1001 | ANV01 | 5.99 |
| 1001 | ANV02 | 9.99 |
| 1001 | ANV03 | 14.99 |
| 1002 | FU1 | 3.42 |
| 1002 | OL1 | 8.99 |
+---------+---------+------------+
2.使用組合查詢
mysql> SELECT vend_id, prod_id, prod_price FROM products WHERE prod_price <= 5 UNION SELECT vend_id, prod_id, prod_price FROM products WHERE vend_id IN (1001, 1002);
+---------+---------+------------+
| vend_id | prod_id | prod_price |
+---------+---------+------------+
| 1003 | FC | 2.50 |
| 1002 | FU1 | 3.42 |
| 1003 | SLING | 4.49 |
| 1003 | TNT1 | 2.50 |
| 1001 | ANV01 | 5.99 |
| 1001 | ANV02 | 9.99 |
| 1001 | ANV03 | 14.99 |
| 1002 | OL1 | 8.99 |
+---------+---------+------------+
注意看:兩條組合語句中SELECT的三個對象分別相同。若刪除最後一個,結果如下。
SELECT vend_id, prod_id, prod_price FROM products WHERE prod_price <= 5 UNION SELECT vend_id, prod_id FROM products WHERE vend_id IN (1001, 1002);
ERROR 1222 (21000): The used SELECT statements have a different number of columns
若有相同的列,但兩個組合之間,列的取值不同,同樣可以顯示結果。我們將第二個查詢中,顯示兩次vend_id
。
mysql> SELECT vend_id, prod_id, prod_price FROM products WHERE prod_price <= 5 UNION SELECT vend_id, prod_id,vend_id FROM products WHERE vend_id IN (1001, 1002);
+---------+---------+------------+
| vend_id | prod_id | prod_price |
+---------+---------+------------+
| 1003 | FC | 2.50 |
| 1002 | FU1 | 3.42 |
| 1003 | SLING | 4.49 |
| 1003 | TNT1 | 2.50 |
| 1001 | ANV01 | 1001.00 |
| 1001 | ANV02 | 1001.00 |
| 1001 | ANV03 | 1001.00 |
| 1002 | FU1 | 1002.00 |
| 1002 | OL1 | 1002.00 |
+---------+---------+------------+
17.2.2 UNION
規則
UNION
必須由兩條或以上的SELECT
語句組成。UNION
中每次查詢必須包含相同的列、表達式或聚集函數。UNION
中,列數據類型必須兼容:類型不必完全相同,但可以在DBMS中轉換。
17.2.3 包含或取消重複的行
UNION
自動排除重複目錄。
若要返回所有值,使用UNION ALL
mysql> SELECT vend_id, prod_id, prod_price FROM products WHERE prod_price <= 5 UNION ALL SELECT vend_id, prod_id, prod_price FROM products WHERE vend_id IN (1001, 1002);
+---------+---------+------------+
| vend_id | prod_id | prod_price |
+---------+---------+------------+
| 1003 | FC | 2.50 |
| 1002 | FU1 | 3.42 |
| 1003 | SLING | 4.49 |
| 1003 | TNT1 | 2.50 |
| 1001 | ANV01 | 5.99 |
| 1001 | ANV02 | 9.99 |
| 1001 | ANV03 | 14.99 |
| 1002 | FU1 | 3.42 |
| 1002 | OL1 | 8.99 |
+---------+---------+------------+
17.2.4 結果排序
ORDER BY
子句應得放在末尾處。
mysql> SELECT vend_id, prod_id, prod_price FROM products WHERE prod_price <= 5 UNION ALL SELECT vend_id, prod_id, prod_price FROM products WHERE vend_id IN (1001, 1002) ORDER BY vend_id,prod_price;
+---------+---------+------------+
| vend_id | prod_id | prod_price |
+---------+---------+------------+
| 1001 | ANV01 | 5.99 |
| 1001 | ANV02 | 9.99 |
| 1001 | ANV03 | 14.99 |
| 1002 | FU1 | 3.42 |
| 1002 | FU1 | 3.42 |
| 1002 | OL1 | 8.99 |
| 1003 | FC | 2.50 |
| 1003 | TNT1 | 2.50 |
| 1003 | SLING | 4.49 |
+---------+---------+------------+
18章 全文本搜索
18.1 全文本搜索
MyISAM
和InnoDB
,前者支持全文本搜索,後者不支持。因此本系列中大部分例表使用InnoDB
,而productontes表使用MyISAM
。
LIKE
和REGEXP
正則表達兩種匹配方式,但缺點是:
- 性能,通配符和正則表達式都是全文匹配,耗時間
- 明確控制,通配符和正則表達式很難明確控制匹配。
- 智能化,通配符和正則表達式都不能提供智能化選擇結果。例如,一個特殊的詞的搜索會返回包含改詞的所有行,而不區分包含單個匹配的行和包含多個匹配的行。
18.2 使用全文檢索
在索引之後,SELECT
使用Match()
、Against()
一起使用。
18.2.1 啓動全文檢索
CREATE TABLE
語句接受FULLTEXT
子句,它給出被索引列的一個逗號分割的列表。例如,
mysql> CREATE TABLE productnotes(note_id int NOT NULL AUTO_INCREMENT, prod_id char(10) NOT NULL, note_date datetime NOT NULL, note_text text NULL, PRIMARY KEY(note_id), FULLTEXT(note_text)) ENGINE = MyISAM;
- 注意:不要在導入數據時開啓
FULLTEXT
,因爲每次導入都需要更新索引,請在導入結束後,再修改表,定義FULLTEXT
。一切都是性能優化方向。
18.2.2 進行全文檢索
SELECT
使用Match()
、Against()
一起使用。
Match()
指定被搜索的列,Against()
指定要使用的搜索表達式。例如,
mysql> SELECT note_text FROM productnotes WHERE Match(note_text) Against('rabbit');
+----------------------------------------------------------------------------------------------------------------------+
| note_text |
+----------------------------------------------------------------------------------------------------------------------+
| Customer complaint: rabbit has been able to detect trap, food apparently less effective now. |
| Quantity varies, sold by the sack load.
All guaranteed to be bright and orange, and suitable for use as rabbit bait. |
+----------------------------------------------------------------------------------------------------------------------+
- 注意:傳遞給
Match()
的值必須與FULLTEXT
定義中的相同。如果指定多個列,必須按照正確次序列出;同時搜索不區分大小寫,除非使用BINARY
。
LIKE
語句同樣可以檢索,但返回的次序不同
mysql> SELECT note_text FROM productnotes WHERE note_text LIKE '%rabbit%';
+----------------------------------------------------------------------------------------------------------------------+
| note_text |
+----------------------------------------------------------------------------------------------------------------------+
| Quantity varies, sold by the sack load.
All guaranteed to be bright and orange, and suitable for use as rabbit bait. |
| Customer complaint: rabbit has been able to detect trap, food apparently less effective now. |
+----------------------------------------------------------------------------------------------------------------------+
雖然同樣檢索出,但是詞rabbit作爲第三個詞的行的等級比作爲第20個詞的行高。同時由於全文本是經過索引的,全文搜索相當快。
18.2.3 使用查詢擴展
- MySQL 4.1.1版本引入
- 首先進行基本全文搜索,找出匹配行。
- MySQL檢查匹配行並選擇所有有用的詞。
- 再次進行全文本搜索,使用所有詞。
簡單全文檢索,未擴展:
mysql> SELECT note_text FROM productnotes WHERE Match(note_text) Against('anvils');
+----------------------------------------------------------------------------------------------------------------------------------------------------------+
| note_text |
+----------------------------------------------------------------------------------------------------------------------------------------------------------+
| Multiple customer returns, anvils failing to drop fast enough or falling backwards on purchaser. Recommend that customer considers using heavier anvils. |
+----------------------------------------------------------------------------------------------------------------------------------------------------------+
增加全文查詢擴展:
mysql> SELECT note_text FROM productnotes WHERE Match(note_text) Against('anvils' WITH QUERY EXPANSION);
+----------------------------------------------------------------------------------------------------------------------------------------------------------+
| note_text |
+----------------------------------------------------------------------------------------------------------------------------------------------------------+
| Multiple customer returns, anvils failing to drop fast enough or falling backwards on purchaser. Recommend that customer considers using heavier anvils. |
| Customer complaint:
Sticks not individually wrapped, too easy to mistakenly detonate all at once.
Recommend individual wrapping. |
| Customer complaint:
Not heavy enough to generate flying stars around head of victim. If being purchased for dropping, recommend ANV02 or ANV03 instead. |
| Please note that no returns will be accepted if safe opened using explosives. |
| Customer complaint: rabbit has been able to detect trap, food apparently less effective now. |
| Customer complaint:
Circular hole in safe floor can apparently be easily cut with handsaw. |
| Matches not included, recommend purchase of matches or detonator (item DTNTR). |
+----------------------------------------------------------------------------------------------------------------------------------------------------------+
分析:第一行包含anvils,因此等級最高。第二行與anvils無關,但與第一行其他詞相關。查詢擴展增加了返回的行數,但也增加了不想要的行的數目。
18.2.4 布爾文本搜索
FULLTEXT
索引也可以使用。細節,
1. 要匹配的詞;
2. 要排斥的詞(縱使包含其他指定的詞);
3. 排序提示(指定某些詞比其他詞重要);
4. 表達式分組;
5. 其他。
演示IN BOOLEAN MODE的作用,
mysql> SELECT note_text FROM productnotes WHERE Match(note_text) Against('heavy' IN BOOLEAN MODE);
+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| note_text |
+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| Item is extremely heavy. Designed for dropping, not recommended for use with slings, ropes, pulleys, or tightropes. |
| Customer complaint:
Not heavy enough to generate flying stars around head of victim. If being purchased for dropping, recommend ANV02 or ANV03 instead. |
+---------------------------------------------------------------------------------------------------------------------------------------------------------+
而匹配heavy,且不包含rope開始的詞:
mysql> SELECT note_text FROM productnotes WHERE Match(note_text) Against('heavy -rope*' IN BOOLEAN MODE);
+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| note_text |
+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| Customer complaint:
Not heavy enough to generate flying stars around head of victim. If being purchased for dropping, recommend ANV02 or ANV03 instead. |
+---------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
全文本布爾操作符:
布爾操作符 | 說明 |
---|---|
+ | 包含,詞必須存在 |
- | 排除,詞必須排除 |
> | 包含,且增加等級值 |
< | 包含,且減小等級值 |
() | 把詞組成子表達式 |
~ | 取消一個詞的排序值 |
* | 詞尾的通配符 |
” “ | 定義一個短語(與單個詞列表不同,它匹配整個短語) |
18.2.5 全文本搜索的使用說明
- 自動忽略3個或以下的詞;
- MySQL帶有內建的非用詞(stopword)表,這些詞總是被忽略;
- 許多詞頻過高,搜索無用。MySQL自動忽略50%以上的詞。此規則不適用於IN BOOLEAN MODE;
- 行數小於3,全文本搜索不返回結果;
- 忽略單引號。例如don’t索引爲dont;
- 不具有詞分隔符的語言(日語)不能恰當返回結果;
- 僅在MyISAM引擎中支持全文本檢索。
- 注意:MySQL暫不支持鄰近操作符。