_2_ SQL 检索数据
本文 DEMO:
https://gitee.com/changsanjiang/SQLDemo/tree/master
SELECT 语句
SQL 语句由简单的英语单词构成. 这些单词称为关键字, 每个SQL语句都是由一个或多个关键字构成的. 最常使用的SQL语句大概就是SELECT语句了. 它的用途是从一个或多个表中检索信息.
**关键字**
作为SQL组成部分的保留字. 关键字不能用作表或列的名字.
为了使用SELECT检索表数据, 必须至少给出两条信息:
- 想选择什么
- 从什么地方选择
下面我们从简单的 SQL SELECT 语句学起吧.
检索单个列
-- 输入:
SELECT prod_name -- 想选择什么
FROM Products; -- 从什么地方选择
如上, 同很多编程语言一样, sql 也支持写注释, 其中 --
即为注释开头, 另外还可以像C语言一样使用/* ... */
来进行注释.
上述语句利用SELECT语句从Products表中检索一个名为prod_name的列. 所需的列名写在SELET关键字之后, FROM关键字指出从哪个表中检索数据. 此语句的输出如下所示:
prod_name |
---|
Fish bean bag toy |
Bird bean bag to |
Rabbit bean bag toy |
**提示: 结束SQL语句**
多条SQL语句必须以分号(;)分隔. 大多数的DBMS不需要在单条SQL语句后加分号, 但也有DBMS可能必须在单条SQL语句后加上分号.
当然, 如果愿意可以总是加上分号, 这并没有坏处.
** 提示: SQL语句和大小写**
请注意, SQL语句不区分大小写, 因此SELECT与select是相同的 同样, 写成Select也没有关系.
不过, 一定要认识到虽然SQL是不区分大小写的, 但是 表名, 列名和值可能有所不同(这依赖于具体的DBMS及其如何配置).
**提示: 使用空格**
在处理SQL语句时, 其中所有空格都被忽略. SQL语句可以写成长长的一行, 也可以分写成多行.
下面这3种写法的作用是一样的
SELECT prod_name
FROM Products;
SELECT prod_name FROM Products;
SELECT
prod_name
FROM
Products;
检索多个列
要想从一个表中检索多个列, 仍然使用相同的SELECT语句. 唯一不同是必须在SELECT关键字后给出多个列名, 列名之间必须以逗号分隔.
**提示: 当心逗号**
在选择多个列时, 一定要在列名之间加上逗号, 但最后一个列名后面不加.
如果加上, 将会出现错误.
-- 输入
SELECT prod_id, prod_name, prod_price
FROM Products;
输出如下:
prod_id | prod_name | prod_price |
---|---|---|
1 | Fish bean bag toy | 12.3 |
2 | Bird bean bag toy | 3.49 |
3 | Rabbit bean bag toy | 2.1 |
**说明: 数据表示
从上述输出可以看到, SQL语句一般返回原始的, 无格式的数据.
数据的格式化是表示问题, 而不是检索问题.
因此, 表示(如吧上面的价格值显示为正确的十进制数值货币金额)一般在显示该数据的应用程序中规定.
通常很少直接使用实际检索出的数据.
检索所有列
除了指定所需的列外(如上所述, 一个或多个列), SELECT语句还可以检索所有的列而不必逐个列出他们. 如下, 使用通配符*
可以做到这一点.
-- 输入
SELECT *
FROM Products;
分析:
如果给定一个通配符*
, 则返回表中所有列. 列的顺序一般是其在表定义中出现的物理顺序, 但并不总是如此. 不过这并不会造成什么问题, 因为通常, 数据返回给应用程序, 还会根据需要进行格式化, 再表示出来.
** 注意: 使用通配符**
一般而言, 除非你确实需要表中的每一列, 否则最好别使用通配符.
虽然使用通配符能让自己省事, 不用明确列出所有列, 但检索不需要的列通常会降低检索和应用程序的性能.
**搜索未知列**
使用通配符有一个大优点. 由于不明确指定列名(因为星号检索每一列), 所以能检索出名字未知的列.
检索不同的值
如果你不想在检索出的数据中出现重复数据, 该怎么办呢? 例如, 你想检索 products 表中所有产品供应商的ID:
-- 输入
SELECT vend_id
FORM Products;
输出: (以后改为模拟器, 第一行为列名, 其余行为检索结果)

因为 products 有9种产品, 所以SELECT语句返回了每条产品的供应商, 但是可以看到在返回的数据中有重复的供应商, 那如何只检索出不同的值?
办法就是使用DISTINCT关键字, 顾名思义, 它指示数据库只返回不同的值.
-- 输入
SELECT DISTINCT vend_id
FROM Products;
分析:
SELECT DISTINCT vend_id 告诉DBMS只返回不同(具有唯一性)的vend_id行, 所以正如下面的输出, 只有3行. 如果使用 DISTINCT关键字, 必须将其放到列名的前面.
输出:

另外注意: DISTINCT关键字作用于所有的列, 不仅仅是跟在其后的那一列.
例如, 你指定 SELECT DISTINCT vend_id, prod_price, 只有在两列数据与其余数据不同时, 才会被列举出来. 一图胜千言, 请看如下输出:
-- 输入(未使用DISTINCT)
SELECT vend_id, prod_price
FROM Products;
输出:

可以看到 DLL01 | 3.49
多次出现. 我们可以使用如下操作, 过滤这几个重复数据行.
-- 输入
SELECT DISTINCT vend_id, prod_price
FROM Products;
输出:

由上, DLL01 | 3.49
只出现一次.
限制结果行数
我们之前使用的SELECT 语句, 会返回指定表中所有匹配的行. 但是如果我们想只返回第一行或者一定数量的行, 该怎么办呢? 这是可行的, 然而遗憾的是, 各种数据库中的这一SEL实现并不相同.
笔者只关注iOS平台, 故此只看一下iOS平台下的SQLite.
SELECT prod_name
FROM Products
LIMIT 5;
分析:
上述代码使用SELECT语句来检索一列数据. LIMIT 5指示DBMS返回不超过5行的数据. 输出请如下图:

现在我们知道了限制返回结果行数, 那如何指定从哪儿开始检索呢? 像这样:
SELECT prod_name
FROM Products
LIMIT 5 OFFSET 5;
分析:
LIMIT 5 OFFSET 5 指示DBMS返回从第5行起的5行数据. LIMIT 5 表示检索出5行数据, OFFSET 5 表示从第5行开始, 包括第5行, 也就是 5, 6, 7, 8, 9.
输出:

在本例中, 由于测试数据只有9种产品, 因此OFFSET 5之后, 就是 5, 6, 7, 8行有数据了. 到第9行就没数据了(从0开始)
**注意: 第0行
第一个被检索的行是第0行, 而不是第1行.
简化写法:
SELECT prod_name
FROM Products
LIMIT 3,5
LIMIT 3, 5
使用这个语法, 逗号之前的值对应的OFFSET, 之后的值对应的LIMIT.