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之后。使用子句的次序不对将产生错误信息。

你可能感兴趣的:(MySQL,sql,mariadb)