系统函数查的是环境,不是数据:引擎版本、当前用户、当前库、连接号、上一次插入的自增值。
Demo 里 sqlite_version() 给 3.53.1——它是本沙箱这个引擎的版本,不是 MySQL 的;
MySQL 那边写 SELECT VERSION()。
last_insert_id() 给 4(刚插进去那行的自增 id);
DATABASE()、USER()、CONNECTION_ID() 在这里没有等价物,跑不了。
上一类算摘要,这一篇是「查自己」。 它几乎不参与业务逻辑,但排查问题的第一步全靠它。 「明明改了却没生效」这种问题,一半是连到了另一台库。
一、版本号:先确认自己连的是谁
SELECT VERSION() 是 MySQL 的写法,给 8.0.x。
本沙箱没有这个函数,对应的是 SELECT sqlite_version(),给 3.53.1。
教材原码是 VERSION(),这一句在本沙箱不执行。
正文里凡出现「教材原码、不在此执行」,都是这个意思。
为什么第一步就敲它:不同版本的语法、函数、默认行为都不一样。
同一个报错在 5.7 和 8.0 上原因可能完全不同,先确认版本能省一半时间。
二、last_insert_id:上一次插入的自增 id
插一行,再问 last_insert_id(),给的就是那行的 id。 Demo 里插入「四班」,拿到 4。
它是「当前连接上一次 INSERT」的值——换一个连接就变了,所以别指望在另一个会话里读到它。
批量插入时它给的是「第一行」的 id,不是最后一个。
这个细节在批量写子表时很关键:拿到第一行的 id,再按行数往后推,才能对上每一行。
三、数据库名、当前用户:教材原码,这里没有
MySQL 里常用这四个:DATABASE() 给当前库名、USER() 给登录用户、CONNECTION_ID() 给连接号、
@@version 也是版本号。
本沙箱是「一个文件一个库」,没有「当前库」这个概念,也没有登录用户,
所以这几个函数没法给等价物。
处理方式:教材里这几句照原样记,但标注「本沙箱不执行」,不硬编一个假结果。
测不出来的东西就写「测不出来」,别编。
四、系统函数能干什么
最实用的是自检:连上先 SELECT VERSION() 确认引擎、SELECT DATABASE() 确认没连错库。
两步五秒钟,能省几小时。
其次是审计:把 USER()、CONNECTION_ID() 写进操作日志,
出问题时能追到是哪个连接干的。 多个人共用一个账号时,这条尤其重要。
但别把它们写进业务逻辑——换个环境值就变了,
测试和线上的行为就不一致了。 判断「是不是生产环境」这种事,该在配置里做,不该在 SQL 里做。
五、动手 Demo:查版本、插一行、再问它的 id
Demo 三段:问版本号、插一行班级、看自增 id 落在哪儿。 这一段没有业务含义,全是「确认环境」的动作。
import _q46 as Q
c = Q.con()
# 版本号:这里问的是 SQLite
c.execute("SELECT sqlite_version() AS v")
# 刚插进去那行的自增 id
Q.run(c, "INSERT INTO classes (name, teacher, room) "
"VALUES ('四班', '唐老师', 'B301')")
c.execute("SELECT LAST_INSERT_ID() AS new_id")
c.execute("SELECT id, name, teacher FROM classes ORDER BY id")
# MySQL 的 DATABASE()/USER()/CONNECTION_ID() 在这里没有等价物
实跑输出:
--------------------------------------------------------------------
第二十九课:系统函数——查环境,不是查数据
--------------------------------------------------------------------
版本号:这里问的是 SQLite 的版本
SQL> SELECT sqlite_version() AS v
v
-------
3.53.1
(1 行)
**`3.53.1` 是本沙箱这个引擎的版本号。**
**MySQL 那边对应的是 `SELECT VERSION()`,会给 `8.0.x`。**
**教材原码是 `VERSION()`,本沙箱没有这个函数,所以不在这儿执行。**
**这一句的用途是「连上之后先确认自己连的是哪个引擎、哪个版本」**,排查问题时第一步就该敲它。
last_insert_id:刚插进去那行的自增 id
SQL> INSERT INTO classes (name, teacher, room) VALUES ('四班', '唐老师', 'B301')
影响 1 行
SQL> SELECT LAST_INSERT_ID() AS new_id
new_id
-------
4
(1 行)
SQL> SELECT id, name, teacher FROM classes ORDER BY id
id name teacher
------------------------
1 一班 马老师
2 二班 孔老师
3 三班 曹老师
4 四班 唐老师
(4 行)
**插进去的那行拿到了 id = 4,`last_insert_id()` 给的就是 4。**
**它是「当前连接上一次 INSERT」的值**,换一个连接就变了。
**批量插入时它给的是「第一行」的 id**,不是最后一个。
**这个细节在批量写子表时很关键**——别拿它去算最后一行的 id。
数据库名、当前用户:教材原码,这里没有
**MySQL 里常用这几个**:`DATABASE()` 给当前库名、`USER()` 给当前登录用户、
`CONNECTION_ID()` 给连接号、`@@version` 也是版本号。
**本沙箱是「一个文件一个库」,没有「当前库」这个概念,也没有登录用户**,
所以这几个函数没法给等价物。 **教材里这几句照原样记,但在这里跑不了。**
系统函数能干什么
**最实用的是「自检」**:连上先 `SELECT VERSION()` 确认引擎、`SELECT DATABASE()` 确认没连错库。
**线上出「明明改了却没生效」的问题,一半是连到了另一台库。**
**其次是审计**:把 `USER()`、`CONNECTION_ID()` 写进日志,**出问题时能追到是哪个连接干的。**
**但别把它们写进业务逻辑**——换个环境值就变了,测试和线上行为不一致。
第一段版本。 3.53.1——这是 SQLite 的版本,不是 MySQL 的。
第二段插入。 影响 1 行,四班进去了。
第三段自增 id。 给 4,因为原来三条记录占了 1、2、3。
再列一遍全表,能看到四班确实在第四行。
30 秒实验
- 再插一行,
LAST_INSERT_ID()会变几? - 在另一个连接里问
LAST_INSERT_ID(),能读到这个 4 吗? SELECT VERSION()在本沙箱会报什么错?试一次。
常见误区
- 把
DATABASE()、USER()写进业务判断。 换环境值就变,测试与线上行为不一致。 - 批量插入后拿
last_insert_id()当最后一个 id。 它给的是第一行的 id。 - 不确认版本就照抄网上的写法。 5.7 和 8.0 的默认行为差很多, 同一个问题可能根本不是同一个原因。
自测三问(点开对答案)
1. MySQL 里查版本、查当前库、查当前用户分别用什么函数? —— `VERSION()`、`DATABASE()`、`USER()`,另有 `CONNECTION_ID()` 给连接号。 2. `LAST_INSERT_ID()` 在批量插入时给哪一个 id? —— 给第一行的自增 id,不是最后一个。 3. 为什么系统函数不该写进业务逻辑? —— 值随环境变化,测试与线上行为就不一致了;这类判断该放配置里。系统函数是最短的一篇。下一篇收尾——cast、if、ifnull 三个最常用的杂项。
- ☐ (本篇完,下一篇 6.8 其他函数)