# 从表中查询数据

> 用明确的列名、别名和过滤条件读取示例表 fruits。

---

LLMS 索引： [llms.txt](/llms.txt)

---

现在 `fruits` 已经有了数据，可以开始读取这些行了。`SELECT *` 返回所有列；列出具体列名，则只返回这些列，并按列名的书写顺序排列。除非加上 `ORDER BY`，否则结果没有确定的行序；即使今天看起来有序，明天也未必如此。

## 本章要点 {#learn}

- 用 `SELECT * FROM table` 读取所有列
- 选择特定列，并控制它们在结果中的顺序
- 将 `SELECT` 与 `WHERE`、`ORDER BY` 组合使用
- 为什么 `SELECT *` 适合临时查询，却在应用代码中存在风险
- 结果列的名称，以及如何修改它们

> [!NOTE] 准备示例表
> 开始本章前，先在练习数据库中运行 `psql -f source/create-table.sql -f source/insert.sql postgres`。这两个文件分别在第 16 章和第 24 章介绍；学习这些 SELECT 章节之前，表必须已经存在。

## 示例 {#example}

```sql {num="6.1" caption="从表中查询数据"}
-- All columns. The order matches CREATE TABLE.
SELECT * FROM fruits ORDER BY id;

-- Specific columns, in the order you list them
SELECT name, id FROM fruits ORDER BY id;

-- Renaming output columns
SELECT id AS fruit_id, name AS fruit_name FROM fruits ORDER BY id LIMIT 3;

-- Combining a filter and an order
SELECT id, name
FROM fruits
WHERE id BETWEEN 2 AND 4
ORDER BY name;

-- Counting rows
SELECT count(*) AS total FROM fruits;
```

先运行 `create-table.sql` 和 `insert.sql`，再运行本章示例。`SELECT *` 按*物理*列顺序返回所有列。明确列出列名，就能完全控制结果的结构；当数据要交给按位置映射列的应用代码时，这一点尤其重要。`AS` 只修改输出中的列名，不会改变表中的任何内容。

`*` 和操作符两侧的空格可以省略；SQL 解析器对空白字符相当宽容。查询分成多行书写很常见，列数超过两列时也推荐这样做。

## 运行示例 {#run}

运行方式：

```text
$ psql -f source/select-from-table.sql postgres
 id  |   name
-----+-----------
   1 | apple
   2 | banana
   3 | cherry
   4 | date
   5 | elderberry
 101 | fruit_1
 102 | fruit_2
 103 | fruit_3
(8 rows)

    name    | id
------------+-----
 apple      |   1
 banana     |   2
 ...
```

## 常见陷阱 {#pitfalls}

- `SELECT * FROM big_table;` 会通过网络取回每一行的每一列，既慢又浪费资源。请列出实际需要的列。
- 输出列名并不保证唯一。`SELECT id, id FROM fruits` 的两列都叫 `id`，应用使用的驱动可能无法妥善处理这种情况。
- 在应用代码中，应优先明确指定列名，而不是使用 `SELECT *`。当表结构中新增一列时，`SELECT *` 的结果结构就会改变，可能使依赖特定列顺序或列数的代码出错。

> [!TIP] 提示
> 探索数据时，可以在 psql 中用 `\x` 切换*扩展显示*：一条记录的每一列各占一行。用这种方式阅读宽行会轻松得多。

> [!NOTE] 动手练习
> 运行 `SELECT * FROM fruits WHERE id > 100;`，只查看生成的那些行。然后运行 `SELECT name FROM fruits ORDER BY name;`，让名称按字母顺序排列。再尝试 `SELECT id || ': ' || name AS label FROM fruits;`，用字符串拼接操作符 `||` 构造一个标签列。

## 下载 {#downloads}

SQL 文件： [select-from-table.sql](/examples/source/select-from-table.sql) · [全部示例文件](/examples/examples.zip) · [准备工作](/#prerequisites)
