一、組合查詢
該章節講述如何利用UNION操作符將多餘SELECT語句組合成一個結果集合。
1、 組合查詢
MySQL允許執行多個查詢,並將結果作爲單個查詢結果返回。
組合查詢的情況:
- 在單個查詢中從不同地的表返回類似結構的數據。
- 對單個表執行多個查詢,按單個查詢返回結果。
2、 創建組合查詢
可用UNION操作符來組合數條SQL查詢,利用UNION可以給出多條SELECT語句,將它們的結果組合成單個結果集。
2.1、使用UNION
UNION的使用很簡單,所需做的只是給出每條SELECT語句,在各條語句之間放上關鍵字UNION。
例子,將價格小於等於5元的產品進行檢索,還要包括那些由生產商1001和1002生產的產品。
MariaDB [course]> SELECT prod_id,prod_price,vend_id
-> FROM products
-> WHERE prod_price <= 5
-> UNION
-> SELECT prod_id,prod_price,vend_id
-> FROM products
-> WHERE vend_id IN (1001,1002);
+---------+------------+---------+
| prod_id | prod_price | vend_id |
+---------+------------+---------+
| FC | 2.50 | 1003 |
| FU1 | 3.42 | 1002 |
| SLING | 4.49 | 1003 |
| TNT1 | 2.50 | 1003 |
| ANV01 | 5.99 | 1001 |
| ANV02 | 9.99 | 1001 |
| ANV03 | 14.99 | 1001 |
| OL1 | 8.99 | 1002 |
+---------+------------+---------+
8 rows in set (0.00 sec)
該例用多條WHERE子句的實現方法如下:
MariaDB [course]> SELECT prod_id,prod_price,vend_id
-> FROM products
-> WHERE prod_price <= 5
-> OR vend_id IN (1001,1002);
組合查詢和多個WHERE條件:多數情況下,兩個方法的查詢結果相同且具有相同的功能。但是對於比較複雜的條件過濾,使用UNION處理更簡單。
2.2、UNION規則
- UNION必須由兩條或以上的SELECT語句組成,語句之間由 UNION進行分隔。
- UNION中的每個查詢必須包含相同的列、表達式或聚集函數(不過各個列不需要以相同的次序出現)
- 列數據類型必須兼容:類型不必完全相同,但是必須是DBMS可以相互轉換的類型。
2.3、包含或取消重複的行
UNION從查詢結果中自動去除了重複的和行,這是UNION的默認行爲,如果需要可以改變。如果想返回所有匹配行,可使用UNION ALL
進行。
MariaDB [course]> SELECT prod_id,prod_price,vend_id
-> FROM products
-> WHERE prod_price <= 5
-> UNION ALL
-> SELECT prod_id,prod_price,vend_id
-> FROM products
-> WHERE vend_id IN (1001,1002);
+---------+------------+---------+
| prod_id | prod_price | vend_id |
+---------+------------+---------+
| FC | 2.50 | 1003 |
| FU1 | 3.42 | 1002 |
| SLING | 4.49 | 1003 |
| TNT1 | 2.50 | 1003 |
| ANV01 | 5.99 | 1001 |
| ANV02 | 9.99 | 1001 |
| ANV03 | 14.99 | 1001 |
| FU1 | 3.42 | 1002 |
| OL1 | 8.99 | 1002 |
+---------+------------+---------+
9 rows in set (0.01 sec)
2.4、對組合查詢結果進行排序
在使用UNION 組合查詢時,只能使用一條ORDER BY子句,它必須出現在最後一條SELECT語句之後。
MariaDB [course]> SELECT prod_id,prod_price,vend_id
-> FROM products
-> WHERE prod_price <= 5
-> UNION
-> SELECT prod_id,prod_price,vend_id
-> FROM products
-> WHERE vend_id IN (1001,1002)
-> ORDER BY vend_id,prod_price;
+---------+------------+---------+
| prod_id | prod_price | vend_id |
+---------+------------+---------+
| ANV01 | 5.99 | 1001 |
| ANV02 | 9.99 | 1001 |
| ANV03 | 14.99 | 1001 |
| FU1 | 3.42 | 1002 |
| OL1 | 8.99 | 1002 |
| FC | 2.50 | 1003 |
| TNT1 | 2.50 | 1003 |
| SLING | 4.49 | 1003 |
+---------+------------+---------+
8 rows in set (0.00 sec)
雖然ORDER BY子句似乎只是最後一條SELECT語句的組成部分,但實際上MySQL將用它來排序所有SELECT語句檢索出的結果。
二、全文本搜索
1、 理解全文本搜索
之前介紹過的搜索機制有LIKE關鍵字和正則表達式。它們存在幾個幾個重要的限制:
- 性能——通配符和正則表達式匹配通常要求MySQL嘗試匹配表的所有行。當搜索的行數逐漸增加會非常耗時。
- 明確控制——很難明確控制匹配的內容,
- 智能化的結果——不能提供一種智能化的選擇結果的方法
使用全文本搜索,不需要分別查看每個行,不需要分別分析和處理每個詞。MySQL創建指定列中各詞的一個索引,搜索可以針對這些詞進行。
並非所有引擎都支持全文本搜索:
兩個最常用的引擎爲MyISAM和InnoDB,前者支持而後者不支持。
2、 使用全文本搜索
爲了進行全文本搜索,必須索引被搜索的列,而且隨着數據的改變不斷地重新索引。在對錶列進行適當設計後,MySQL會自動進行所有的索引和重新索引。
在索引之後,SELECT可以與Match()
和Against()
一起使用以實現搜索 。
2.1、啓用全文本搜索支持
一般在創建表時會啓用全文本搜索。CREATE TABLE語句
接受FULLTEXT子句
,它給出被索引的列。
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;
這是創建products表時的SQL語句,其中使用了FULLTEXT子句,還使用了MyISAM引擎。
MySQL使用了FULLTEXT(note_text)
來指示對它進行索引,在定義之後,MySQL自動維護該索引,在增加、更新、刪除行時,索引隨之自動更新。
2.2、進行全文本搜索
在索引之後,使用兩個函數執行全文本搜索。其中Match()
指定被搜索的列,Against()
指定要使用的搜索表達式。
MariaDB [course]> 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. |
+----------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)
此SELECT語句檢索單個列note_text,Match(note_text)
指示MySQL針對指定的列進行搜索,Against('rabbit')
指定詞rabbit爲搜索文本。
使用全文本搜索返回以文本匹配的良好程度排序的數據,兩個行都包含要匹配的單詞,但是所匹配單詞在某一行出現的位置越靠前該行的等級就越高。具有較高等級的行優先返回。
Match()和Against()用來建立一個計算列(別名爲rank),此列包含全文本搜索計算出的等級值。
等級值根據行中詞的數目、唯一詞的數目、整個索引中詞的總數以及包含該詞的行的數目計算出來。
例子中,不包含搜措詞的等級爲0,位置靠前的等級越高。
全文本搜索將那些等級爲0的行進行派出,按照等級以降序排序。
2.3、使用查詢擴展
查詢擴展用來設法放寬所返回的全文本搜索結果的範圍。
在使用查詢擴展時 ,MySQL對數據和索引進行兩遍掃描來完成搜索:
- 首先,進行一個基本的全文本搜索,找出與搜索條件匹配的所有行;
- MySQL檢查這些匹配行並選擇所有有用的單詞。
- MySQL再次進行全文本搜索,這次不僅使用原來的條件,而且還使用所有有用的詞。
利用查詢擴展,能找出可能相關的結果,即使它們並不精確包含所查找的詞。
SELECT note_text
FROM productnotes
WHERE Match ( note_text ) Against ( 'anvils' WITH QUERY EXPANSION );
2.4、布爾文本搜索
使用布爾方式搜素,可以提供關於如下內容的細節:
- 要匹配的詞
- 要排斥的詞(如果某行包含這個詞,則不返回該行。)
- 排列提示(指定某些詞比其他詞更重要)
- 表達式分組
- 另外一些內容
匹配包含heavy但不包含有以rope開頭的單詞的行。
MariaDB [course]> 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)
2.5、全文本搜索的使用說明
- 在索引全文本數據時,短詞被忽略且從索引中刪除。短詞定義爲那些3個字母以下的凡此
- MySQL帶有一個內建的非用詞(stopword)l列表,這些詞在索引全文本數據時總是被忽略。
- 許多詞的出現頻率很高,搜索它們沒有用處。因此,MySQL規定了一條50%規則,如果一個詞出現在50%以上的行中,則將它作爲一個非用詞忽略。50%規則不用於IN BOOLEAN MODE.
- 如果表中的行數少於3行,則全文本搜索不返回結果
- 忽略詞中的單引號。don`t 索引爲dont
- 不具有詞分隔符的語言不能恰當地返回全文本搜索結果
- 僅在MyISAM數據庫 引擎中支持全文本搜索