Before start
文内所使用样例来自MySQL Crash Course官网,后续内容均以样例展开。 脚本样例地址
其中包含create.sql and populate.sql两个文件,下载了脚本后,可以使用它们来创建和填充学习所用的表。以下是步骤:
source create.sql
(制定create.sql的完全路径)。populate.sql
文件填充各个新表。SELECT语句
其用途是从一个或多个表中检索信息,为了使用SELECT检索表数据,必须至少给出两条信息(想选择什么以及从哪里选择)
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关键字使用大写,而对列和 表名使用小写,这样做使代码更易于阅读和调试。最佳的方法是按照大小写的惯例,且使用时保持一致。
要想从一个表中检索多个列,使用相同的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 |
+---------+----------------+------------+
除了指定所需的列外,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 |
+---------+---------+----------------+------------+----------------------------------------------------------------+
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)
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
将检索出第二行而不是第一行。
迄今为止使用的SQL例子只通过列名引用列。也可能会使用完全限定的名字来引用列。(即同时使用表和名字)
SELECT prodcuts.prod_name
FROM products;
这条语句在功能上和没有使用完全限定的表名的语句相同,但是这里指定了一个完全限定的列名。
表名也可以是完全限定的,如下所示:
SELECT products.prod_name
FROM test.products;
这条语句在功能上也等于刚使用的那条语句,假定products表确实位于test库中。
该章节讲述如何使用SELECT语句的ORDER BY子句,根据需要来排序检索出的数据。
下面的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)
经常需要按不止一个列进行数据排序,为了按多个列排序,只要指定列名,列名之间用逗号分隔开即可。
下面的代码检索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
进行排序。
数据排序不限于升序排序,这只是默认的排序顺序,还可以使用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 BY
和LIMIT
的组合,能够找出一个列中最高或最低的值。下面例子演示找到最昂贵物品的价格:
SELECT prod_price
FROM products
ORDER BY pord_price DESC
LIMIT 1;
+------------+
| prod_price |
+------------+
| 55.00 |
+------------+
ORDER BY
子句的位置,在给出ORDER BY
子句时,应该保证它位于FROM
子句之后。如果使用LIMIT
,它必须位于ORDER BY
之后。使用子句的次序不对将产生错误信息。