🦏 第3章 查询操作
📄 一句话概括

select 只做两件事:挑列、挑行。 这一篇只管挑列—— 列可以是表里的、可以是算出来的、也可以是常量。 Demo 里 SELECT * 出三行四列;height * 2 出 345.00; my table 里那个叫 select 的列不加反引号直接语法错; 一条 SQL 写成五行照样跑——引擎只看分号。

📝 本章和前面几章的关系

上一章讲「怎么说」,这一篇开始真查数据。 select 是全书出现最多的关键字, 后面 16 章都在给它加各种子句。 顺序要记住:select(挑列)→ from(从哪张表)→ where(筛行)→ group by。 再往后是 having → order by → limit。 这一篇只碰最前面两个。

一、select 的基本形状:挑哪几列

最小的一句是 SELECT 列名 FROM 表名;。 select 后面写要哪几列,from 后面写从哪张表取。 SELECT * 是「所有列」,写起来省事,但产品代码里尽量别用: 表一加字段,取回来的列就变了,程序里按下标取值的地方会错位; 大字段(TEXT、BLOB)也会被白白拉回来。 列的顺序自己定,不必跟建表顺序一致;同一列也可以写两次(少见但合法)。

二、列可以算:表达式、常量、函数

select 后面不只放列名,还能放表达式:height * 2、price * 0.9、concat(name, '同学')。 算出来的东西没有名字,得给别名。 也能放常量:SELECT '固定值' AS tag, id FROM students——这一招在导数据、加标记时很常用。 还能完全不带表:SELECT 1 + 1; 在 8.0 里合法,用来测连接通不通最快。 本沙箱也支持。

三、特殊列名:反引号是保命符

列名叫 select、表名带空格、字段名是 order——这些不报错的办法只有一个:用反引号包起来。 反引号在 MySQL 里是「标识符引用」,和字符串的单引号是两回事。 标准 SQL 用双引号,但 MySQL 默认把双引号当字符串,所以还是用反引号。 这就是命名规则那条「别用关键字」的真实原因:不是洁癖, 是每次写它都得记得加反引号,早晚漏一次。

四、换行说明:一条语句可以写很多行

引擎只认分号,不认换行。 你把 select、from、where 各写一行,或者全挤一行,结果一样。 但人要在乎:一个子句一行,where 里的每个 and 各占一行, 这样别人(和三个月后的你)才看得懂。 图形工具里还有个实际影响:编辑器里选中哪一段就只跑哪一段,所以语句之间空一行,方便单独跑。

五、小结

教材小结:select 语句用于查询,select * 取所有列、也可以只取指定列;一条语句可以分多行书写。 本课补三条:一是产品代码别写星号,列会随表结构漂移; 二是列可以是表达式、常量、函数,算出来的都要起别名;三是特殊列名一律反引号,别赌。

六、动手 Demo:从星号到指定列,再到反引号

Demo 五段:先 SELECT * 看全表,再只挑两列,再让列参与运算,然后撞一次特殊列名, 最后看一条 SQL 写成五行。 这一篇的每一段都在回答同一个问题:select 后面到底能放什么。

import sqlite3
c = sqlite3.connect(":memory:")
# 这里直接借样例库(六张表)
import _q46 as Q
c = Q.con()

c.execute("SELECT * FROM classes")          # 所有列
c.execute("SELECT name, teacher FROM classes")   # 指定列
c.execute("SELECT name, height * 2 AS double_h "
          "FROM students LIMIT 3")        # 列参与运算

# 特殊列名要反引号
c.execute("CREATE TABLE `my table` (`select` TEXT, `full name` TEXT)")
c.execute("SELECT `select`, `full name` FROM `my table`")

# 一条 SQL 可以写很多行,引擎只看分号
c.execute("""SELECT id, name, height
FROM students
WHERE class_id = 1""")

实跑输出:

--------------------------------------------------------------------
第九课:select 的第一层——挑列
--------------------------------------------------------------------

  查全部列:星号,方便但别写进产品代码
  SQL> SELECT * FROM classes
  id     name     teacher     room
  ------------------------------------
  1      一班     马老师      A101
  2      二班     孔老师      A102
  3      三班     曹老师      B201
  (3 行)

  **三行四列全出来了,但列的顺序依赖建表顺序。**
  **产品代码里写星号,表一加字段,取到的列就变了。**

  查指定列:要哪几列写哪几列
  SQL> SELECT name, teacher FROM classes
  name     teacher
  -----------------
  一班     马老师
  二班     孔老师
  三班     曹老师
  (3 行)

  **列的顺序可以自己定**,不必跟建表顺序一致。

  列可以参与运算:查出来的不一定是原样
  SQL> SELECT name, height, height * 2 AS double_h FROM students LIMIT 3
  name     height     double_h
  -----------------------------
  张伟     172.50     345.00
  王芳     160.20     320.40
  李娜     165.00     330.00
  (3 行)

  **`height * 2` 不是表里的列,是查的时候算出来的——所以必须给它一个别名(下一节专讲)。**

  特殊列名:带空格、带关键字,都要反引号
  SQL> SELECT `select`, `full name` FROM `my table`
  select     full name
  ---------------------
  a          张伟
  (1 行)

  **表名带空格、列名叫 select,全得用反引号包起来。**
  **所以命名规则里那条「别用关键字」不是洁癖,是省事。**

  换行说明:一条 SQL 可以写很多行
  SQL> SELECT id, name, height FROM students WHERE class_id = 1
  id     name     height
  -----------------------
  1      张伟     172.50
  2      王芳     160.20
  6      杨帆     175.10
  9      周涛     174.00
  (4 行)

  **引擎只看分号,不在乎你在哪换行。** **但人要在乎:一个子句一行,比挤成一行好读得多。**

第一段星号。 三行四列全出来,列顺序就是建表顺序。 第二段挑列。 只要 name, teacher 两列,顺序可以自己定,不必跟建表一致。 第三段列运算。 height * 2 算出 345.00、320.40、330.00, 表头就是那个表达式——所以下一节讲别名。 第四段特殊列名。 表名 my table 带空格、列名叫 select,全靠反引号才过。 第五段换行。 写成五行照样跑出四行结果,引擎只看分号。

30 秒实验

  1. SELECT * FROM classes 与 SELECT id, name, teacher, room FROM classes 结果一样吗?
  2. (先想再跑)SELECT 1 + 1; 不带 from 能跑吗?
  3. 把 SELECT * 换成 SELECT name, id,列的顺序变了吗?

常见误区

  1. 产品代码写 select *。 表加一个字段,取回的列就多一个,按下标取值的代码立刻错位。
  2. 特殊列名不加反引号。 报的是语法错,指向的位置还很靠前,看起来像是前面写错了。
  3. 把一条 SQL 挤成一行。 能跑,但改的时候找不到该改哪一段,而且图形工具里没法只选中一半运行。
自测三问(点开对答案) 1. `SELECT *` 有什么风险? —— 列随表结构变化,程序按下标取会错位;还会把 TEXT/BLOB 这类大字段白拉回来。 2. select 后面能放什么? —— 列名、表达式、常量、函数;算出来的列建议起别名。 3. 表名或列名撞上关键字怎么办? —— 用反引号包起来(MySQL 写法);标准 SQL 用双引号,但 MySQL 默认把双引号当字符串。

算出来的列没有名字,下一篇专门讲怎么给它起名——别名,以及它在 where 里为什么有时用不了。

相关笔记