MySQL必知必會——組合查詢、全文本搜索

一、組合查詢

該章節講述如何利用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數據庫 引擎中支持全文本搜索
發佈了115 篇原創文章 · 獲贊 30 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章