MySQL組合查詢與全文搜索.md

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規則

  1. UNION必須由兩條或以上的SELECT語句組成。
  2. UNION中每次查詢必須包含相同的列、表達式或聚集函數。
  3. UNION中,列數據類型必須兼容:類型不必完全相同,但可以在DBMS中轉換。

17.2.3 包含或取消重複的行

     注意觀察17.2.1兩種方式返回的數目,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 全文本搜索

     兩個最常用的數據庫引擎爲MyISAMInnoDB,前者支持全文本搜索,後者不支持。因此本系列中大部分例表使用InnoDB,而productontes表使用MyISAM
     前文中已經介紹過LIKEREGEXP正則表達兩種匹配方式,但缺點是:
- 性能,通配符和正則表達式都是全文匹配,耗時間
- 明確控制,通配符和正則表達式很難明確控制匹配。
- 智能化,通配符和正則表達式都不能提供智能化選擇結果。例如,一個特殊的詞的搜索會返回包含改詞的所有行,而不區分包含單個匹配的行和包含多個匹配的行。

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版本引入
         查詢擴展(QUERY EXPANSION)用來放寬全文搜索結果的範圍。倘若想找出全部anvils的詞,同時想要找出相關的所有其他行。對數據和索引進行兩遍掃描
    1. 首先進行基本全文搜索,找出匹配行。
    2. MySQL檢查匹配行並選擇所有有用的詞。
    3. 再次進行全文本搜索,使用所有詞。

簡單全文檢索,未擴展:

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 布爾文本搜索

     另一種全文本檢索形式,稱爲布爾方式(boolean mode)。即使沒有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 全文本搜索的使用說明

  1. 自動忽略3個或以下的詞;
  2. MySQL帶有內建的非用詞(stopword)表,這些詞總是被忽略;
  3. 許多詞頻過高,搜索無用。MySQL自動忽略50%以上的詞。此規則不適用IN BOOLEAN MODE
  4. 行數小於3,全文本搜索不返回結果;
  5. 忽略單引號。例如don’t索引爲dont
  6. 不具有詞分隔符的語言(日語)不能恰當返回結果;
  7. 僅在MyISAM引擎中支持全文本檢索。
    • 注意:MySQL暫不支持鄰近操作符。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章