MySQL必知必會——檢索、排序數據

Before start
文內所使用樣例來自MySQL Crash Course官網,後續內容均以樣例展開。 腳本樣例地址
其中包含create.sql and populate.sql兩個文件,下載了腳本後,可以使用它們來創建和填充學習所用的表。以下是步驟:

  1. 創建一個新數據源(爲安全考慮,不要使用已有的數據源)。
  2. 保證選擇新數據源(使用mysql命令行程序,使用USE命令)。
  3. 執行create.sql 腳本。使用mysql命令行程序,可給出source create.sql (制定create.sql的完全路徑)。
  4. 重複前面的步驟,用populate.sql文件填充各個新表。

一、檢索數據

SELECT語句
其用途是從一個或多個表中檢索信息,爲了使用SELECT檢索表數據,必須至少給出兩條信息(想選擇什麼以及從哪裏選擇)

1、檢索單個列

SELECT prod_name
FROM products;

上述語句從products表中檢索一個prod_name的列,所需的列名在SELECT關鍵字之後給出,FROM關鍵字指出從其中檢索的表名。輸出如下所示:

+----------------+
| prod_name      |
+----------------+
| .5 ton anvil   |
| 1 ton anvil    |
| 2 ton anvil    |
| Detonator      |
| Bird seed      |
| Carrots        |
| Fuses          |
| JetPack 1000   |
| JetPack 2000   |
| Oil can        |
| Safe           |
| Sling          |
| TNT (1 stick)  |
| TNT (5 sticks) |
+----------------+

SQL語句不分大小寫,因此SELECT和select語句是相同的,許多SQL開發人員喜歡對所有SQL關鍵字使用大寫,而對列和 表名使用小寫,這樣做使代碼更易於閱讀和調試。最佳的方法是按照大小寫的慣例,且使用時保持一致。

2、檢索多個列

要想從一個表中檢索多個列,使用相同的SELECT語句。唯一的不同是必須在SELECT關鍵字之後給出多個列名,列名之間 必須以逗號分隔。
從products中檢索3個列:

SELECT prod_id,prod_name,prod_price
FROM products;

使用SELECT語句從表products中檢索數據,制定了三個列名,列名之間用逗號分隔。輸出如下:

+---------+----------------+------------+
| prod_id | prod_name      | prod_price |
+---------+----------------+------------+
| ANV01   | .5 ton anvil   |       5.99 |
| ANV02   | 1 ton anvil    |       9.99 |
| ANV03   | 2 ton anvil    |      14.99 |
| DTNTR   | Detonator      |      13.00 |
| FB      | Bird seed      |      10.00 |
| FC      | Carrots        |       2.50 |
| FU1     | Fuses          |       3.42 |
| JP1000  | JetPack 1000   |      35.00 |
| JP2000  | JetPack 2000   |      55.00 |
| OL1     | Oil can        |       8.99 |
| SAFE    | Safe           |      50.00 |
| SLING   | Sling          |       4.49 |
| TNT1    | TNT (1 stick)  |       2.50 |
| TNT2    | TNT (5 sticks) |      10.00 |
+---------+----------------+------------+

3、檢索所有列

除了指定所需的列外,SELECT語句還支持檢索所有的列而不必逐個列出它們,這可通過在實際的列名位置使用星號(*)通配符來達到。

SELECT *
FROM products;

如果給定一個通配符(*),則返回表中所有列。列的順序一般是在列在表定義中出現的順序,但有時候並不適合這樣的,表的模式變化(如添加或刪除)可能會導致順序的變化。

+---------+---------+----------------+------------+----------------------------------------------------------------+
| prod_id | vend_id | prod_name      | prod_price | prod_desc                                                      |
+---------+---------+----------------+------------+----------------------------------------------------------------+
| ANV01   |    1001 | .5 ton anvil   |       5.99 | .5 ton anvil, black, complete with handy hook                  |
| ANV02   |    1001 | 1 ton anvil    |       9.99 | 1 ton anvil, black, complete with handy hook and carrying case |
| ANV03   |    1001 | 2 ton anvil    |      14.99 | 2 ton anvil, black, complete with handy hook and carrying case |
| DTNTR   |    1003 | Detonator      |      13.00 | Detonator (plunger powered), fuses not included                |
| FB      |    1003 | Bird seed      |      10.00 | Large bag (suitable for road runners)                          |
| FC      |    1003 | Carrots        |       2.50 | Carrots (rabbit hunting season only)                           |
| FU1     |    1002 | Fuses          |       3.42 | 1 dozen, extra long                                            |
| JP1000  |    1005 | JetPack 1000   |      35.00 | JetPack 1000, intended for single use                          |
| JP2000  |    1005 | JetPack 2000   |      55.00 | JetPack 2000, multi-use                                        |
| OL1     |    1002 | Oil can        |       8.99 | Oil can, red                                                   |
| SAFE    |    1003 | Safe           |      50.00 | Safe with combination lock                                     |
| SLING   |    1003 | Sling          |       4.49 | Sling, one size fits all                                       |
| TNT1    |    1003 | TNT (1 stick)  |       2.50 | TNT, red, single stick                                         |
| TNT2    |    1003 | TNT (5 sticks) |      10.00 | TNT, red, pack of 10 sticks                                    |
+---------+---------+----------------+------------+----------------------------------------------------------------+

4、檢索不同的行(去重)

SELECT返回所有匹配的行,但是如果你不想要每個值每次都出現。假如你想要得出products表中產品的所有供應商ID:

SELECT vend_id
FROM products;
+---------+
| vend_id |
+---------+
|    1001 |
|    1001 |
|    1001 |
|    1002 |
|    1002 |
|    1003 |
|    1003 |
|    1003 |
|    1003 |
|    1003 |
|    1003 |
|    1003 |
|    1005 |
|    1005 |
+---------+

SELECT語句返回14行(但表中只有4個供應商的ID),因爲products表中列出了14個產品。那麼,如何檢索出有不同值的列表呢
解決辦法就是DISTINCT關鍵字,顧名思義,此關鍵字就是指示MySQL只返回不同的值。

SELECT DISTINCT vend_id
FROM products;

SELECT DISTINCT vend_id告訴MySQL只返回不同的vend_id的行,因此只返回4行。
如果使用DISTINCT關鍵字,它必須放在列名的前面。

+---------+
| vend_id |
+---------+
|    1001 |
|    1002 |
|    1003 |
|    1005 |
+---------+
4 rows in set (0.00 sec)

不能部分使用DISTINCT ,該關鍵字應用於所有列而不僅是前置它的列,如果給出SELECT vend_id,prod_price FROM products; 除非指定的兩個列相同的行兩個字段的值完全相同,否則所有的行都將 被檢索出來。

MariaDB [test]> SELECT vend_id,prod_price  FROM products;
+---------+------------+
| vend_id | prod_price |
+---------+------------+
|    1001 |       5.99 |
|    1001 |       9.99 |
|    1001 |      14.99 |
|    1003 |      13.00 |
|    1003 |      10.00 |
|    1003 |       2.50 |
|    1002 |       3.42 |
|    1005 |      35.00 |
|    1005 |      55.00 |
|    1002 |       8.99 |
|    1003 |      50.00 |
|    1003 |       4.49 |
|    1003 |       2.50 |
|    1003 |      10.00 |
+---------+------------+
14 rows in set (0.00 sec)

5、限制結果

SELECT語句返回所有匹配的行,它們可能是指定表中的每個行,爲了返回第一行或者前幾行,可使用LIMIT子句。

SELECT prod_name
FROM products
LIMIT 5;

此句使用SELECT語句檢索單個列,LIMIT 5指定MySQL返回不多於5行。

+--------------+
| prod_name    |
+--------------+
| .5 ton anvil |
| 1 ton anvil  |
| 2 ton anvil  |
| Detonator    |
| Bird seed    |
+--------------+
5 rows in set (0.00 sec)

爲得出下一個5行,可以指定要檢索的開始行和行數,如下所示:

SELECT prod_name 
FROM products
LIMIT 5,5;

LIMIT 5,5指示MySQL返回從第5行開始的5行。第一個數字爲開始的位置,第二個數字爲要檢索的行數。

+--------------+
| prod_name    |
+--------------+
| Carrots      |
| Fuses        |
| JetPack 1000 |
| JetPack 2000 |
| Oil can      |
+--------------+
5 rows in set (0.00 sec)

所以,帶一個值的LIMIT 總是從第一行開始的,給出數爲返回的行數。
帶兩個值的LIMIT可以指定從行號爲第一個值的位置開始。
ATTENTION: 檢索出來的第一行爲行0而不是行1。因此,LIMIT 1,1將檢索出第二行而不是第一行。

6、使用完全限定的列名、表名

迄今爲止使用的SQL例子只通過列名引用列。也可能會使用完全限定的名字來引用列。(即同時使用表和名字)

SELECT prodcuts.prod_name
FROM products;

這條語句在功能上和沒有使用完全限定的表名的語句相同,但是這裏指定了一個完全限定的列名。

表名也可以是完全限定的,如下所示:

SELECT products.prod_name
FROM test.products;

這條語句在功能上也等於剛使用的那條語句,假定products表確實位於test庫中。

二、排序檢索數據

該章節講述如何使用SELECT語句的ORDER BY子句,根據需要來排序檢索出的數據。

1、排序數據

下面的SQL語句返回某個數據庫表的單個列,但看其輸出並沒有特定的順序。

SELECT prod_name
FROM products;
+----------------+
| prod_name      |
+----------------+
| .5 ton anvil   |
| 1 ton anvil    |
| 2 ton anvil    |
| Detonator      |
| Bird seed      |
| Carrots        |
| Fuses          |
| JetPack 1000   |
| JetPack 2000   |
| Oil can        |
| Safe           |
| Sling          |
| TNT (1 stick)  |
| TNT (5 sticks) |
+----------------+
14 rows in set (0.00 sec)

其實,檢索出的數據並不是按照隨機的順序進行顯示的。如果不排序,數據一般將以它在底層表中出現的順序顯示。一般爲數據最初添加到表中的順序。如果後來數據進行過更新和刪除,則此順序將會受到MySQL重用回收存儲空間的影響。因此,如果不明確控制的話,不能依賴該排序順序。關係數據庫設計理論認爲,如果不明確規定排序順序,則不該嘉定檢索出數據的順序有意義。

子句:SQL語句由子句組成,有些子句是必需的,有些則是可選的。一個子句通常由一個關鍵字和所提供的數據所構成。

爲了明確地排序用SELECT語句檢索出的數據,可使用ORDER BY子句。

SELECT prod_name
FROM products
ORDER BY prod_name;

這條語句除了指示MySQL對prod_name列以字母順序排序數據的ORDER BY子句外,與上面相同。

+----------------+
| prod_name      |
+----------------+
| .5 ton anvil   |
| 1 ton anvil    |
| 2 ton anvil    |
| Bird seed      |
| Carrots        |
| Detonator      |
| Fuses          |
| JetPack 1000   |
| JetPack 2000   |
| Oil can        |
| Safe           |
| Sling          |
| TNT (1 stick)  |
| TNT (5 sticks) |
+----------------+
14 rows in set (0.00 sec)

通過非選擇列進行排序,通常,ORDER BY子句中使用的列將是爲顯示所選擇的列。但是 ,實際上並不一定要這樣,用檢索的列排序數據也是完全合法的。

MariaDB [test]> SELECT prod_name 
    -> FROM products
    -> ORDER BY prod_price;
+----------------+
| prod_name      |
+----------------+
| TNT (1 stick)  |
| Carrots        |
| Fuses          |
| Sling          |
| .5 ton anvil   |
| Oil can        |
| 1 ton anvil    |
| TNT (5 sticks) |
| Bird seed      |
| Detonator      |
| 2 ton anvil    |
| JetPack 1000   |
| Safe           |
| JetPack 2000   |
+----------------+
14 rows in set (0.00 sec)

2、按多個列排序

經常需要按不止一個列進行數據排序,爲了按多個列排序,只要指定列名,列名之間用逗號分隔開即可。
下面的代碼檢索3個列,並按其中兩個列對結果進行排序——首先按價格,後按名稱排序。

SELECT prod_id,prod_price,prod_name
FROM products
ORDER BY prod_price,prod_name;
+---------+------------+----------------+
| prod_id | prod_price | prod_name      |
+---------+------------+----------------+
| FC      |       2.50 | Carrots        |
| TNT1    |       2.50 | TNT (1 stick)  |
| FU1     |       3.42 | Fuses          |
| SLING   |       4.49 | Sling          |
| ANV01   |       5.99 | .5 ton anvil   |
| OL1     |       8.99 | Oil can        |
| ANV02   |       9.99 | 1 ton anvil    |
| FB      |      10.00 | Bird seed      |
| TNT2    |      10.00 | TNT (5 sticks) |
| DTNTR   |      13.00 | Detonator      |
| ANV03   |      14.99 | 2 ton anvil    |
| JP1000  |      35.00 | JetPack 1000   |
| SAFE    |      50.00 | Safe           |
| JP2000  |      55.00 | JetPack 2000   |
+---------+------------+----------------+

重要的是理解在按多個列排序時,排序完全按照所規定的順序進行。換句話說,對於上述例子的輸出,僅在多個行具有相同的prod_price值時纔會對產品按照prod_name進行排序。如果prod_price值是唯一的,則不會按照prod_name進行排序。

3、指定排序方向

數據排序不限於升序排序,這只是默認的排序順序,還可以使用ORDER BY子句按照降序對數據進行排序。爲了進行降序排序,必須指定DESC關鍵字。
下面按價格以降序排序產品:

SELECT prod_id,prod_price,prod_name
FROM products
ORDER BY prod_price DESC;
+---------+------------+----------------+
| prod_id | prod_price | prod_name      |
+---------+------------+----------------+
| JP2000  |      55.00 | JetPack 2000   |
| SAFE    |      50.00 | Safe           |
| JP1000  |      35.00 | JetPack 1000   |
| ANV03   |      14.99 | 2 ton anvil    |
| DTNTR   |      13.00 | Detonator      |
| TNT2    |      10.00 | TNT (5 sticks) |
| FB      |      10.00 | Bird seed      |
| ANV02   |       9.99 | 1 ton anvil    |
| OL1     |       8.99 | Oil can        |
| ANV01   |       5.99 | .5 ton anvil   |
| SLING   |       4.49 | Sling          |
| FU1     |       3.42 | Fuses          |
| FC      |       2.50 | Carrots        |
| TNT1    |       2.50 | TNT (1 stick)  |
+---------+------------+----------------+

如果打算用多個列排序怎麼辦? 下面例子以產品價格降序排序,再對產品名排序。

SELECT prod_id,prod_price,prod_name
FROM products
ORDER BY prod_price DESC,prod_name;
+---------+------------+----------------+
| prod_id | prod_price | prod_name      |
+---------+------------+----------------+
| JP2000  |      55.00 | JetPack 2000   |
| SAFE    |      50.00 | Safe           |
| JP1000  |      35.00 | JetPack 1000   |
| ANV03   |      14.99 | 2 ton anvil    |
| DTNTR   |      13.00 | Detonator      |
| FB      |      10.00 | Bird seed      |
| TNT2    |      10.00 | TNT (5 sticks) |
| ANV02   |       9.99 | 1 ton anvil    |
| OL1     |       8.99 | Oil can        |
| ANV01   |       5.99 | .5 ton anvil   |
| SLING   |       4.49 | Sling          |
| FU1     |       3.42 | Fuses          |
| FC      |       2.50 | Carrots        |
| TNT1    |       2.50 | TNT (1 stick)  |
+---------+------------+----------------+

分析:DESC關鍵字只應用到直接位於其前面的列名。
在上例中,只對prod_price列指定DESC,對prod_name列不指定。因此,prod_price列以降序排序,prod_name列(在每個價格內)還是以標準的升序排序。
在多個列上降序排序 如果想在多個列上降序排序,必須對每個列指定DESC關鍵字。
DESC相反的關鍵字是ASC,在升序排序時可以指定它。但實際上,ASC沒有多大用處,因爲默認排序方式就是升序的,既不指定DESC又不指定ASC,則假定爲ASC

使用ORDER BYLIMIT的組合,能夠找出一個列中最高或最低的值。下面例子演示找到最昂貴物品的價格:

SELECT prod_price
FROM products
ORDER BY pord_price DESC
LIMIT 1;
+------------+
| prod_price |
+------------+
|      55.00 |
+------------+

ORDER BY子句的位置,在給出ORDER BY 子句時,應該保證它位於FROM子句之後。如果使用LIMIT,它必須位於ORDER BY之後。使用子句的次序不對將產生錯誤信息。

發佈了115 篇原創文章 · 獲贊 30 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章