SELECT 从表中读取行
你向 SQLite 数据库提出的每个问题,都从 SELECT 开始。它的意思是:从这张表里,把满足这些条件的行的这些列给我。今天我们只关注前两部分:列和表。筛选放在下一篇文档。
最简单的查询:
SELECT * 表示“所有列”。FROM products 指定表。结果是每条记录一行,包含全部四列。分号结束语句。
这就是完整的结构:SELECT <columns> FROM <table>;。
选择特定的列
在探索数据时,* 很方便。在真正的代码中,你几乎总是想写出自己真正关心的列名:
你会得到两列,顺序和你要求的一样。SELECT 列表中的顺序决定结果中的顺序,不必和表中列的顺序一致。
为什么要优先用这种写法,而不是 SELECT *?有两个原因。第一,传输(或从文件中读出)的数据更少,表的列一多,这就很重要。第二,下个月有人给表加了一列,你的查询依然稳定。SELECT * 会悄悄开始返回更多数据,按位置解包行的应用代码就可能因此出错。
SELECT 不只能取数据,还能计算
SELECT 列表里的列不一定是原始的列名,可以是任何表达式:算术运算、函数调用、字符串拼接、常量。SQLite 会对每一行计算这个表达式。
第四列在表中并不存在,是 SQLite 逐行算出来的。字符串函数、日期、条件表达式,什么都可以这样用。SELECT 列表是加工数据的地方,而不只是取数据。
你甚至可以不写 FROM 子句直接 SELECT,把 SQLite 当计算器用:
一行,三列。在把表达式放进真正的查询之前,可以先用这种方式测试它的效果。
用 AS 给列起别名
当你计算出一列时,SQLite 会给它一个默认名字,通常就是表达式本身,比如 price * stock。这既难看又不稳定。用 AS 给这一列起个正式的名字:
别名就是这一列在结果集中的名字。阅读输出时,这关系到可读性;对按列名取值的应用代码来说(用 row["inventory_value"] 而不是 row[1]),这一点更加重要。
AS 关键字可以省略,price * stock inventory_value 的效果完全一样,但还是写出来吧。这样意图更清楚,也能避免读者把漏掉的逗号误当成别名。
也给表起别名
你还可以给表本身起一个简短的别名。只有一张表时用处不大,但一旦开始做连接,这个习惯就会带来回报:
现在 p 代表 products。p.name 这种带点的写法明确指出了列来自哪张表。只有一张表时这只是多余的字符;连接三张表时,它是让查询保持可读的唯一办法。
结果中的字面量和常量
你可以把真实的列和常量值混在一起。想给行打标记或填一个占位值时很有用:
每一行都会得到同样的 'USD' 和 1。当你用 UNION 合并多条查询的结果,需要一个标记列来区分来源时,就会用到这种写法。
关于 NULL
有些列是空的:插入时没有给值,或者这一列没有默认值。SQLite 用 NULL 表示“没有值”,在 SELECT 结果中,NULL 会显示为空白或字面上的 NULL,取决于你用的工具。
看第二行。price 是 NULL,price * 2 也是 NULL:任何涉及 NULL 的算术运算结果都是 NULL。这是 SQL 结果让人困惑的最常见原因之一,后面有专门的一页来讲。现在只需要注意:NULL 会在表达式中传染。
要点回顾
SELECT <columns> FROM <table>;是每条查询的结构。- 在真正的代码中明确列出列名;
SELECT *留给探索数据时用。 SELECT列表可以包含任何表达式,不只是列名。- 用
AS给计算出的列和表起正式的名字。 NULL会在算术运算中传播:结果看起来不对时,记得想想它。
下一步:用 WHERE 筛选
到目前为止,每条查询都会返回表中的所有行。WHERE 子句用来缩小范围:按价格、名称、日期,或任何结果为真或假的表达式来挑选行。这就是下一篇文档的内容。
常见问题
SQLite 中 SELECT 的基本语法是什么?
SELECT <columns> FROM <table>;。列可以是用逗号分隔的列表(SELECT name, email FROM users),可以是表示所有列的 *,也可以是任意表达式,比如 price * quantity。FROM 子句指定要读取的表,分号结束语句。
在 SQLite 中应该用 SELECT * 吗?
在命令行里随便看看表里有什么时,用它没问题。在应用代码中,请列出你真正需要的列。SELECT * 会把你的代码和当前的表结构绑在一起:明天加一列,每条查询都会悄悄返回更多数据,按位置解包行的代码就可能因此出错。
如何在 SELECT 结果中重命名列?
用 AS 给列或表达式起别名:SELECT price * quantity AS total FROM orders。别名会成为结果集中的列名,这对可读性很重要,对按列名读取结果的代码也很重要。AS 关键字可以省略,但为了清晰最好保留。