零代码应用开发·第 13 章·3 学时

连上数据库

一个 .db 文件装下整套台账。先把表结构定下来,再写代码。

本章精髓 数据库与文件的区别,在于能查、能改、不会乱。存进文件的数据,找一条要从头翻;存进数据库,一句话就能筛出来,而且每次改动要么全部生效,要么全部不生效。这是"真数据"与"存下来的一堆字"的分界。

学完本章后,你应该能够:

  1. 说清数据库与文件在查找与修改上的差别,判断一份数据该用哪一种;
  2. 读懂一份表结构,指出哪个字段是主键、哪个字段用来关联另一张表;
  3. 用增、删、改、查四类语句完成一次完整的借还登记;
  4. 说清提交这一步的作用,并解释漏掉它会出现什么现象;
  5. 在动手写代码之前先确认表结构,并说清分表的理由。
配套演示文件 第13章演示_两张表沙盘.html 第13章演示_一张表还是两张表.html 第13章演示_建库.py 第13章演示_借还登记.py 第13章演示_看表.py

一个 .db 文件,装下整套台账

成品 · 两张表 · 先要表结构

先看成品怎么用,再打开那个文件看看里面装的是什么。

1.1本章成品:社团物资借还登记

话筒、转接头、拖线板这类东西借出去容易,收回来难。成品是一个登记工具:登记借出、登记归还、查某件物资现在在谁手上、列出所有还没还回来的。数据存在一个 items.db 文件里,跟着程序走。

命令提示符 · 实际运行结果
1 登记借出 2 登记归还 3 查在谁手上 4 列出未归还 5 删除物资 0 退出 请选择:1 物资名称:无线话筒 A 借用人:林晓 已登记: 林晓 借走「无线话筒 A」,时间 2026-05-14 15:20 请选择:1 物资名称:无线话筒 A 借用人:赵鹏 「无线话筒 A」还在 林晓 手上,不能重复借出。 请选择:4 未归还共 2 件: 无线话筒 A — 林晓 — 2026-05-14 15:20 拖线板 — 周敏 — 2026-05-14 15:22

"还在谁手上"这一句是数据库查出来的,不是程序自己记着的

1.2那个 .db 文件里装的是什么

items.db 双击打不开,用记事本打开是乱码。但它并不神秘,里面就是两张表。运行看表脚本,能把它原样打印出来:

第13章演示_看表.py 的输出节选
===== 表:items ===== id | name | note 1 | 无线话筒 A | 带电池 2 | 无线话筒 B | ……共 5 行 ===== 表:records ===== id | item_id | borrower | borrow_at | return_at 1 | 1 | 林晓 | 2026-05-14 15:20 | (空) 2 | 4 | 周敏 | 2026-05-14 15:22 | (空) ……共 2 行

两张表:一张记物资,一张记借还流水。流水表里没有物资名称,只有一个 item_id,写着 1 或者 4,指向物资表里对应的那一行。归还时间那一栏是空的,就表示这件东西还没还回来。

打开 第13章演示_两张表沙盘.html,那里的两张表可以当堂点着改,看每一次操作到底动了哪一行。

1.3为什么不用一个 txt,或者一张表格

这份数据存进文本文件也不是不行。差别在往后:

存成文件.txt / .csv
查一条要把整个文件读进来,再一行行判断。改一条要把整个文件重写一遍。

写到一半程序中断,文件就废了。两个人同时开着改,后保存的会盖掉先保存的
存进数据库.db
查一条写一句条件,由数据库负责筛,程序拿到的已经是结果。改一条只动那一行,其余部分不受影响。

一次改动要么全部生效,要么全部不生效,不会留下改了一半的状态。

数据量小的时候,两边差别不明显。决定用哪一种,看的不是现在有多少条,而是这份数据将来要不要反复查询和修改。台账、登记、记录这类数据,通常一开始就该放进数据库。

讨论一份只写一次、以后只读不改的数据,例如一份已经定稿的名单,用文件存还是用数据库存?如果这份名单要供三个不同的程序读取呢?

1.4本章新技巧:分层生成,先要表结构

直接说"帮我做一个借还登记工具",得到的是一份可以运行的完整代码,表结构藏在里面。跑起来之后才发现字段设计不合适,这时候麻烦就来了:改代码只是改代码,改表结构却要连已经录进去的数据一起动。数据越多,返工的代价越大。

所以本章的提问分成两步。第一步只要表结构,不要任何代码,把它当成一份设计稿来读:有几张表、每张表有哪些字段、哪个是主键、哪些允许为空、为什么这样分表。读懂并确认之后,第二步才让它按这份结构写代码。中间隔着的这一次确认,是本章最值得花的时间。

代码改错了重写一遍就好,表结构改错了,还要把已经录进去的数据搬一遍。

1.5可直接复制的提示词

发给 AI第一步 · 只要表结构,不要代码
我要做一个社团物资借还登记工具,用 SQLite 存数据。 使用场景:登记某件物资被谁借走、登记归还、查某件物资现在在谁手上、 列出所有还没还回来的、把报废的物资从台账里删掉。 请先只给我表结构:需要几张表、每张表有哪些字段、每个字段是什么类型、 哪个是主键、哪些字段允许为空、哪个字段用来关联另一张表。 用表格列出来,再附上建表的 SQL 语句。 【不要写任何 Python 代码】我确认之后再让你写。 另外用一段中文说明:为什么这样分表,而不是全部塞进一张表; 以及"还没归还"这件事,你打算用哪个字段来表示。
发给 AI第二步 · 按确认的结构写代码
表结构我已确认,就按上面那一版,不要再调整字段。 请写 Python 脚本,用标准库 sqlite3,不要引入任何需要 pip 安装的库。 【要求】 ① 五个功能各写成一个独立函数:登记借出、登记归还、查在谁手上、列出未归还、删除物资; ② 数据库文件名 items.db,按脚本自身所在的位置查找,不存在时自动建库建表; ③ 查询一律用问号占位符传参,不要用字符串拼接拼 SQL; ④ 每一次改动之后都要提交,并打印一行中文结果,说明改了什么、影响了几条; ⑤ 一件物资已经借出且没有归还时,不允许重复借出,打印提示告知在谁手上; ⑥ 最后写一段简单的命令行菜单,输入数字选功能。 每一段代码前加一行中文注释。
发给 AI加功能 · 表结构仍然不动
现在要加一个功能:查某个人一共借了哪些东西,还没还的排在前面。 【不要改动】已有的表结构与已经写好的五个函数。 新功能写成一个独立的函数,通过 SQL 查询实现,不要把整张表读进来再用 Python 筛。 如果这个功能确实需要新增字段才能做到,请先说明需要加什么、为什么, 等我确认之后再写代码。 只给出新增的那几行。

这三段提示词里的几条要求,分别对应后面要讲的知识点:

先只给表结构,不要写任何 Python 代码
本章方法:表结构定错,后面每个功能都要返工,数据也要跟着搬
说明为什么这样分表,以及用哪个字段表示未归还
知识点 04、06:分表的理由与空值的用法,都要在动手之前想清楚
按脚本自身所在的位置查找 items.db
知识点 08:写成绝对路径时,换台机器就连不上库
一律用问号占位符传参,不要拼接字符串
知识点 05:拼接出来的 SQL 会把使用者输入的内容当成命令执行
每次改动之后都要提交,并打印影响了几条
知识点 07:漏掉提交时不报错、不留痕,打印条数是唯一能察觉的线索
用标准库 sqlite3,不引入需要安装的库
知识点 01:sqlite3 随 Python 一同提供,机房网络下不必冒安装失败的风险

1.6大模型的常见偏差

不等确认就直接给出完整代码。 这是本章最需要防的一种。它会把表结构和代码一起交出来,你还没来得及看结构,注意力就被代码吸走了。"不要写任何 Python 代码"这句必须单独成行写清楚。

引入需要额外安装的数据库库。 它常会用功能更全的数据库工具库。这类库在正式项目里是合理选择,在本课程里的代价是要先安装,并且把一件本来单文件就能解决的事情复杂化。

用字符串拼接拼出 SQL。 拼接写起来更省事,它有时会这样给。问题是使用者输入的内容会被当成 SQL 的一部分执行。要求里写明用问号占位符,拿到代码后也要检查一遍。

漏掉提交,或者只在部分函数里提交。 常见的情形是查询函数正常、修改函数不生效。验收的办法很简单:改一条,关掉程序,重新打开再查一次。

备用方案 现场生成不顺时,直接使用 第13章演示_建库.py第13章演示_借还登记.py,表结构与第一步得到的设计稿一致。没有安装 DB Browser 的机器,用 第13章演示_看表.py 把两张表原样打印出来。完全跑不起 Python 的机器,用两个网页演示件代替:表怎么变、漏掉 WHERE 会怎样、孤儿记录长什么样,都能在网页里当堂演一遍。

表、主键与关联 本章重点

SQLite · 字段类型 · 主键 · 关联

本章的核心内容集中在这一部分和下一部分。

本章要学的术语 · 八个
01单文件数据库SQLite
02表与字段类型table / type
03主键primary key
04关联foreign key
05增删改查SQL / CRUD
06条件查询WHERE
07事务与提交transaction / commit
08程序与数据分离code / data

这八个术语会原样出现在数据库文档、建表语句与报错信息里。前四个在本部分讲解,后四个在第三部分讲解。

2.1四个知识点,一个一个看

01单文件数据库:一个文件就是整个库
DB
items.db
两张表都在里面

用记事本打开,开头写着 SQLite format 3

现象:文件夹里多出一个 items.db,两万来字节,双击打不开。

概念:SQLite 是一个不需要安装、不需要单独启动服务的数据库,整个数据库就是磁盘上的一个文件,并且随 Python 一同提供。用文本编辑器打开它是乱码,但开头十六个字节写着 SQLite format 3,这是它的身份标记。程序和这个文件放在一起,一起拷走就能在别的机器上继续用。

类比:一本能上锁的账本,随身带得走,不必先去开一间账房。

02表与字段类型:建表时就定死
id
name
note
1
无线话筒 A
带电池
2
无线话筒 B
(空)
INTEGER
TEXT
TEXT

每个字段的类型在建表时就定好了

现象:打开 items.db,看到的是两张表格,和表格软件里的样子差不多。

概念:数据库里的数据存在(table)里,一行一条记录,一列一个字段,这一点与表格软件相同。区别在于建表时就要为每个字段规定类型TEXT 存文字,INTEGER 存整数。类型定死之后,往整数字段里填汉字会被拒绝,数据因此不容易乱。

类比:花名册。表格软件的花名册可以随手在"年龄"栏写"保密",数据库的不行。

03主键:这一行的唯一编号
id
name
1
无线话筒 A
2
无线话筒 B
3
投影转接头

名称可以重复,编号不会

现象:两张表的第一列都叫 id,1、2、3 顺着排下去。

概念:主键(primary key)是用来唯一标识一条记录的字段,同一张表里绝不重复。物资可以重名,借用人可以同名,但 id 一定不同。建表时写上 AUTOINCREMENT,新增一行时由数据库自动给号。有了主键,别的地方才能准确指认某一条记录。

类比:学号。全校可能有三个张伟,学号只有一个。

04关联:两张表靠一个编号对上
items · 物资台账
records · 借还流水
id 1 无线话筒 A
item_id 1 林晓
id 4 拖线板
item_id 4 周敏

流水表里不写名称,只写编号

现象:records 表里没有物资名称,只有一个 item_id,写着 1 或者 4。

概念:数据分成多张表之后,靠一个字段互相指认,这种关系叫关联,用来指过去的那个字段称为外键(foreign key)。好处在改动时才看得出来:物资改名只需改 items 表里的一处,所有借还记录跟着对。如果把名称直接抄进每一条流水,改名就要改几十行,还容易漏掉几条。

类比:成绩表上只写学号不写姓名,姓名去花名册里查。学生改名时,花名册改一次就够了。

打开 第13章演示_一张表还是两张表.html,把同一批数据用两种设计各摆一遍,然后给一件物资改个名,看两边各要改几行。这件事说一百句不如自己点一次。

本章方法 先画表结构,再动手写代码。字段定错,后面每一个功能都要返工。

2.2表结构:两张表长什么样

动手之前先把表定下来。这份建库脚本可以直接运行,运行完就得到一个装好表结构的 items.db。

第13章演示_建库.py全文 · 可直接运行
import sqlite3
from pathlib import Path

DB = Path(__file__).with_name('items.db')

# ① 已有旧库先删掉,保证每次生成的内容一致
if DB.exists():
    DB.unlink()

conn = sqlite3.connect(DB)

# ② 物资表:一件物资一行。id 是主键,name 不允许重复
conn.execute('''
CREATE TABLE items (
    id   INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT    NOT NULL UNIQUE,
    note TEXT
)''')

# ③ 借还流水表:借一次记一行。item_id 指向 items 表的 id
conn.execute('''
CREATE TABLE records (
    id        INTEGER PRIMARY KEY AUTOINCREMENT,
    item_id   INTEGER NOT NULL,
    borrower  TEXT    NOT NULL,
    borrow_at TEXT    NOT NULL,
    return_at TEXT
)''')

# ④ 写入五件示例物资。问号是占位符,实际的值由后面那个括号提供
for name, note in [('无线话筒 A', '带电池'),
                   ('无线话筒 B', ''),
                   ('投影转接头', 'Type-C 转 HDMI'),
                   ('拖线板', '五米'),
                   ('三脚架', '')]:
    conn.execute('INSERT INTO items (name, note) VALUES (?, ?)', (name, note))

# ⑤ 提交:不写这一行,上面做的改动全部不算数
conn.commit()
conn.close()

print('已建立', DB.name)
input('按回车键结束')
id INTEGER PRIMARY KEY AUTOINCREMENT
主键,由数据库自动编号。新增一行不必自己想编号,也不会重复。 不设主键时,两行内容完全相同就再也分不开,改一条会连带改到另一条
name TEXT NOT NULL UNIQUE
文字类型,不允许为空,不允许重复。约束写在建表时,此后由数据库自己把关。 不写 UNIQUE 时,台账里可以出现两件同名物资,查在谁手上就分不清是哪一件
item_id INTEGER NOT NULL
关联字段,存的是物资表里那一行的 id。流水表因此不必抄物资名称。 把名称直接抄进流水时,物资改名要改几十行,漏掉几条就对不上了
return_at TEXT
没写 NOT NULL,所以允许为空。空就表示还没还,不必另设一个"是否归还"的字段。 另设一个是否归还的字段时,它和归还时间可能对不上,得同时维护两处
conn.commit()
提交。上面所有改动到这一步才真正写进文件。 漏掉时程序照常打印"已建立",关掉再打开却是一个空库,而且没有任何报错
Path(__file__).with_name('items.db')
数据库文件就放在脚本旁边。两个文件一起拷走,换台机器仍然找得到。 写成绝对路径时,换一台计算机就连不上库,而且报错说的是"没有这张表"

四句 SQL、条件与提交 本章重点

增删改查 · WHERE · commit · 孤儿记录

这一部分讲的两件事,一件让你能干活,一件让你不出事。

3.1另外四个知识点

05增删改查:数据库只做这四件事
做什么
语句
INSERT
SELECT
UPDATE
DELETE

四个词,覆盖绝大多数需求

现象:代码里出现了几个大写的英文词:SELECT、INSERT、UPDATE、DELETE。

概念:SQL(Structured Query Language,结构化查询语言)是与数据库沟通的语言。它要做的事只有四类,行业里合称增删改查。这四句都是固定句式,把表名和条件换掉就能用在别处。本章不必记住语法,能读懂一句 SQL 在动哪张表、动哪几行就够了。

类比:点菜的固定句式。句子结构不变,换的只是菜名和份数。

06条件查询:让数据库替你筛
存成文件 全部读进来再逐条判断数据越多越慢
存进数据库 一句 WHERE直接给结果

筛选由数据库完成,程序拿到的已经是结果

现象:查"还没还回来的"只写了一句 WHERE return_at IS NULL,屏幕上就只剩那两条。

概念:WHERE 后面跟的是筛选条件,数据库据此只把符合条件的记录交回来。IS NULL 表示这个字段是空的。本例用空的归还时间表示还没还,因此不必另设一个"是否归还"的字段:同一件事只有一处记着,就不会出现两处对不上的情况。

类比:把条件告诉图书管理员,让他找出来,不必自己一排排书架翻过去。

07事务与提交:不写这一行,改动不算数
改了但没提交关掉就没了
commit()真正落到文件上
漏掉时程序不报错,数据却没存住

这是本章最容易踩的一处

现象:程序说"已登记",关掉再打开,数据却不见了。

概念:数据库的改动先记在一次事务(transaction)里,执行 commit() 才真正写进文件。这样安排是为了让一组改动要么全部生效,要么全部不生效,中途出错不会留下改了一半的状态。代价是漏写这一行时程序不会报错,数据却没有存住。检验办法只有一步:改一条,关掉程序,重新打开再查一次。

类比:转账不会只扣不加。两边都记上,这笔才算完成。

08程序与数据分离:两个文件要一起搬
只拷 .py 程序能跑一条记录都没有
.py 加 .db 两个一起拷数据都在

代码丢了可以重新生成,数据丢了没有办法

现象:把 .py 拷到另一台电脑,程序能跑,但一条记录都查不到。

概念:程序和数据是两样东西:代码在 .py 里,数据在 .db 里,缺一样都不成。交付时两个文件要一起给,路径也要按脚本自身所在位置去找。数据库文件同时也是最需要备份的那一个,代码丢了还能再让大模型写一份,数据丢了没有别的办法。

类比:账本和账房先生得一起走。只带走一个,另一头就停摆。

3.2四句 SQL,一句一句看

四个功能各对应一句 SQL。下面这四句就是登记工具的全部核心,其余都是外围。

第13章演示_借还登记.py节选 · 四句 SQL
-- 增:登记借出,往流水表插一行
INSERT INTO records (item_id, borrower, borrow_at) VALUES (?, ?, ?)

-- 查:这件物资现在在谁手上
SELECT records.borrower, records.borrow_at
FROM records JOIN items ON items.id = records.item_id
WHERE items.name = ? AND records.return_at IS NULL

-- 改:登记归还,把归还时间填上
UPDATE records SET return_at = ?
WHERE item_id = ? AND return_at IS NULL

-- 删:把一件物资从台账删掉
DELETE FROM items WHERE name = ?
INSERT INTO 表 (字段…) VALUES (…)
往表里加一行。字段名的个数与后面问号的个数必须一一对应。 个数对不上时立刻报错。这一类错误反而是好事,不会留下坏数据
JOIN items ON items.id = records.item_id
把两张表按编号对起来。对上之后,一句话就能同时取出物资名称与借用人。 不 JOIN 时只能查到 item_id 这个数字,看不出到底是哪件物资
WHERE return_at IS NULL
筛选条件:只要归还时间为空的那些。 漏掉这一句时,已经还回来的记录也会被算成未归还,而且屏幕上看不出异常
UPDATESET 字段 = ? WHERE
改哪张表的哪个字段,改哪几行。执行前先用同样的条件 SELECT 一次,看会命中几行再动手。 漏掉 WHERE 时,这张表里所有记录的归还时间都会被填上,而且没有撤销
DELETE FROMWHERE
删掉符合条件的行。同样要先查一次再删。 漏掉 WHERE 时整张表被清空,语句本身完全合法,不会有任何提示
? 占位符
实际的值由后面那个括号提供,不要用字符串拼接把值直接接进 SQL。 用拼接时,借用人如果输入了一段 SQL,就会被当成命令执行,这类问题叫 SQL 注入
WHERE 是这一章唯一真正危险的地方。 UPDATE 与 DELETE 漏掉 WHERE,语句本身完全合法,数据库不会拦你,屏幕上也不会有任何提示,只是整张表被改掉或者清空。纪律只有一条:执行前先用同样的条件 SELECT 一次,看会命中几行再动手。这与第 10 章的预演是同一个动作。

3.3删掉一件物资,它的记录还在,却查不出来了

把还没还回来的"拖线板"从台账删掉之后,records 表里那条未归还记录依然存在,但"列出未归还"再也查不到它,因为 JOIN 到 items 表时找不到对应的行。

屏幕上没有任何报错,数据也没有丢,只是对不上了。这类问题叫数据完整性问题,本章的代码没有防它。

这是本课程里出现的第三种故障形态。第一种会报错,停下来;第二种不报错但结果不对,比如平均分偏低两分;这一种连结果都是对的,只是有一条记录从此谁也查不到。第13章演示_两张表沙盘.html 里点一次"删除物资",就能看见那条流水孤零零地留在表里。

讨论一件还在别人手上的物资被从台账里删掉,你认为程序应该怎么处理?直接拒绝删除、允许删除但一并删掉流水、还是允许删除并保留流水?三种做法各自会在什么时候出问题?如果这件物资是真的丢了、再也回不来了呢?

完整演示与一条行业事实

定结构 · 建库 · 四种操作 · 看表

从一张纸上的表结构,到一个能拷着走的 .db 文件。

4.1演示步骤

1
用第一段提示词拿到表结构,先不要代码
拿到的应当是一张字段表加一段建表语句,外加一段分表理由。出现 Python 代码,说明那句约束没起作用,重发一次
产出:一份表结构设计稿
2
读懂表结构,当场加一个字段
例如加一个"预计归还日期"。先自己判断它该加在哪张表:加在物资表里,同一件物资借十次就只能记一个日期;加在流水表里,每一次借出各记各的。判断完再问大模型,对照两边的理由
产出:一处经过讨论的修改
3
用第二段提示词生成代码,先运行建库脚本
运行完文件夹里应当出现 items.db。此时它只有表结构和几件示例物资,流水表是空的
产出:一个 items.db
4
登记两条借出,再试一次重复借出
同一件物资借两次,第二次应当被拒绝并说明在谁手上。这一条是判断程序有没有真的去查数据库的最快办法
产出:两条流水与一次拒绝
5
打开 .db,看见真实的表和数据
用 DB Browser for SQLite 打开最直观;机房没装的,运行看表脚本,一样能把两张表原样打印出来。重点看 records 表:item_id 是数字,return_at 是空的
产出:表内容的截图
6
登记一条归还,再看一次表
那一行的 return_at 从空变成了时间,其余各行没有变化。这就是"改一条只动那一行"的实际样子
产出:改动前后的对照
7
把 .py 与 .db 一起拷到另一个位置,确认数据都在
再试一次只拷 .py 不拷 .db,看程序会怎么样。两次对照,把"程序与数据是两样东西"这件事看实
产出:两次拷贝的对照结果

4.2前沿三分钟:一种被装在几十亿台设备上的数据库

每章固定栏目 · 一条与本章内容相关的行业动态

本章用的 SQLite 并不是一个教学用的简化品。按部署数量算,它很可能是世界上使用最广的数据库:手机应用的本地数据、浏览器的书签与浏览记录、许多桌面软件的配置与缓存,用的都是它。原因正是它的那个特点,一个文件就是一个库,不需要单独安装和启动,嵌进任何程序里都不添麻烦。

另一件值得知道的事与保存年限有关。SQLite 的开发者把文件格式的长期兼容当成正式承诺对外声明,美国国会图书馆也把它列入推荐的数据集长期保存格式。理由是它的格式有完整的公开文档,即便将来没有任何软件支持,也能照着文档把数据读出来。

这一点对选型有实际影响:挑存储格式时,除了现在好不好用,还要问一句十年后还打不打得开。公开有文档的格式,比某个在线服务的私有格式更经得起时间。

讨论一份社团台账打算保存十年,你会选 CSV、SQLite,还是某个在线表格服务?三者在"十年后还能不能打开"这件事上,各自的风险是什么?如果这份数据同时还要多人同时录入呢?

上机实验

三选一 · 六步 · 先定结构

上机环节由此开始,当堂完成并提交。

5.1三个题目,任选其一

题目 A
社团物资借还

登记借出与归还,查某件物资在谁手上,列出未归还。

通用
题目 B
读书笔记库

按书名、标签、日期检索笔记,一本书可以有多条笔记。

偏文科
题目 C
实验样品台账

样品编号与批次,记录状态流转,查当前处于某一状态的样品。

偏理工

三个题目都要求至少两张表、有关联字段、四类操作齐全。共同点是同一个主体会有多条记录:一件物资借还多次、一本书有多条笔记、一个样品经历多个状态。允许更换题材。

5.2上机六步

1
用第一段提示词拿到表结构,抄进文档
拿到之后先别急着要代码。逐个字段问自己:这个字段是什么类型、能不能为空、为什么放在这张表。答不上来的字段,回去问清楚
产出:一张字段表
2
自己改动一处表结构,并写清理由
加一个字段,或者把某个字段换一张表放。改动本身不必高明,但要能说出为什么。这一处改动是验收项
产出:一处修改与一句理由
3
用第二段提示词生成代码,建库并录入至少六条数据
数据要覆盖不同情况,例如已归还的与未归还的都要有,否则查询功能验不出来
产出:一个 .db 与六条以上记录
4
四类操作各走一遍,每一步之后都看一次表
增、查、改、删各一次。每次操作之后打开数据库看一眼,确认表里确实变了,不要只看屏幕上的提示
产出:四张操作截图
5
关掉程序重新打开,再查一次,确认数据还在
这一步专门用来验证提交有没有写全。数据不见了,回去检查每个修改函数末尾
产出:数据留存的验证
6
组内互测:把 .py 与 .db 一起发给同组同学
请他在自己的机器上完成一次增和一次查。重点确认路径没有写死、数据能被读出来
产出:一行互测记录

5.3共同验收标准

至少两张表,且有关联字段 一张表通过编号指向另一张 看建表语句,确认存在一个指向另一张表主键的字段
每张表都有主键 同一张表里不会有两行分不开 看建表语句里有没有 PRIMARY KEY
四类操作齐全并各演示一次 增、查、改、删都能跑通 四张截图,每张都能看出表里发生了什么变化
关掉重开数据仍在 说明提交写全了 改一条,退出程序,重新打开再查一次
查询用 SQL 完成,不是读进来再筛 条件写在 WHERE 里 看查询函数里有没有把整张表取出来再用 Python 判断
传参用问号占位符 没有用字符串拼接拼 SQL 在代码里搜加号,检查有没有把变量接进 SQL 字符串
改过一处表结构并说明理由 改动是自己判断的,不是照抄 文档里有一句话写明改了什么、为什么

5.4常见错误与处理

程序说登记成功,关掉再开数据不见了
漏掉了 conn.commit()
在每一处改动之后补上提交,查询语句不需要
sqlite3.OperationalError: database is locked
另一个程序正开着这个库,多半是 DB Browser 没关
关掉查看工具,或者在其中点一下写入更改,再运行脚本
no such table: items
库还没建,或者连到了另一个目录下的空库
先运行建库脚本;确认路径用的是脚本自身所在位置
no such column: 某个字段名
表结构改了,但旧的 .db 还在,里面仍是老结构
删掉旧库重新建;已有数据不能删的,用 ALTER TABLE 加字段
UNIQUE constraint failed: items.name
往有唯一约束的字段里插了重复的值
插入之前先查一次,已存在就走另一条分支,不要直接插
查出来是一串数字,看不出是哪件物资
只查了流水表,没有 JOIN 物资表
加上 JOIN 把两张表按编号对起来,再取名称字段
执行一次修改,整张表都被改了
UPDATE 或 DELETE 漏掉了 WHERE
改之前先用同样的条件 SELECT 一次,看会命中几行再动手
拷给同学,程序能跑但一条记录都没有
只拷了 .py,没有拷 .db
两个文件一起拷,并确认程序按自身所在位置去找数据库

5.5提交内容

脚本与数据库
.py 文件与 .db 文件,缺一不可
压缩成一个包
表结构表格
表名、字段、类型、是否可空、主键与关联字段
一张表格
数据截图
数据库里两张表的实际内容
一张截图
四种操作各一张
增、查、改、删的运行结果
四张截图

提交方式:按教师提供的作业模板填写,文档开头注明所选题目。提交渠道见课堂通知,当堂提交。

5.6再进一步(选做)

让数据库自己拒绝那种会把数据搞乱的删除:在建表时为关联字段加上外键约束,删除一件仍有未归还记录的物资时,由数据库直接报错,而不是让流水变成孤儿。

做完会发现一个需要权衡的问题:约束越严,录入时越麻烦;约束越松,数据越容易对不上。报废一件确实丢失的物资时,严格的约束反而会拦住你。这条线画在哪里,取决于谁来录入、录错了由谁负责,不是一个纯技术问题。

本章小结

本章五条结论

  1. 数据库与文件的区别,在于能查、能改、不会乱。台账、登记、记录这类要反复查询和修改的数据,一开始就该放进数据库。
  2. 先定表结构,再写代码。代码改错了重写一遍就好,表结构改错了,已经录进去的数据也要跟着搬。
  3. 增删改查四句话覆盖绝大多数需求。其中 UPDATE 与 DELETE 的 WHERE 一旦写错或漏写,影响的是整张表,而且没有撤销。
  4. 提交不写,改动不算数。程序不报错,数据也不在。检验只有一步:改一条,关掉,重开再查。
  5. 程序和数据是两样东西,交付时要一起给。代码丢了还能让大模型重写一份,数据丢了没有别的办法。
本章脉络