入职第一天:把老板的订单表变成库
入职第一天,老板发来订单导出文件:「明天告诉我昨天卖了多少。」你环顾四周--公司连个数据库都没有。
学 · 40 min
01什么是数据库 / 表 / 行 / 列:和 Excel 的对应关系
场景老板丢来一个订单导出文件,你只会用 Excel 打开它。今天起,同样的数据要换一种存放方式。
对应关系一句话:数据库 = 整个工作簿文件,表 = 一个 sheet,行 = 一条订单记录,列 = 一个字段(id、金额、时间……)。本质区别在约束和访问方式:Excel 的单元格里塞什么都可以,数据库的每一列有类型(金额必须是数字)和可空性(支付时间可以没有),访问统一走 SQL 而不是鼠标点选。
-- 表在数据库里的样子:列有类型,行是一条条订单 select id, user_id, status, total_amount, created_at from orders limit 3;易错Excel 里「没填」和「填了 0」长得差不多;数据库里 NULL(没发生)和 0(发生了、值为零)是两个世界,D3 整天都在讲它。
02Docker 起 PostgreSQL 16,psql 连进去
场景公司连个数据库都没有,你今天要自己搭一个--但不能往笔记本上裸装软件。
Docker 一条命令起一个干净的 PostgreSQL 16 容器,删掉重来毫无负担。
psql是 PG 官方命令行客户端,连进去就是你的操作台。装完先做三件事:进容器、开 psql、建库。docker run -d --name pg16 -e POSTGRES_PASSWORD=dev -p 5432:5432 postgres:16 docker exec -it pg16 psql -U postgres CREATE DATABASE shop; \c shop易错容器删了数据就没了。要持久化就加
-v pgdata:/var/lib/postgresql/data挂个卷;练习期无所谓,崩了重灌反而干净。036 个元命令:\l \dt \d \x \timing
场景进了 psql 就是一块黑屏--先学会「环顾四周」。
元命令是 psql 客户端的功能,不是 SQL:
\l列出所有库、\dt列出当前库的表、\d 表名看表结构(字段、类型、可空、默认值)、\x把宽结果竖排显示、\timing on显示每条 SQL 的耗时(W6 优化周全靠它)。\dt -- 库里有哪些表 \d orders -- orders 的完整结构 \timing on -- 之后每条 SQL 都带耗时易错元命令以反斜杠开头、不带分号,只在 psql 里有效。换任何别的客户端(代码里连库)它们都不存在。
04CREATE TABLE:orders 的字段类型你来定
场景建表没有标准答案,字段类型是业务判断题:这张表在你眼里是什么。
每个字段回答两个问题:什么类型、能不能为空。id 用 uuid(导出文件里就是无序编号);金额用
numeric(10,2)定点小数,不是 float;status 用 int 存状态码;created_at 必填,paid_at 允许 NULL--可空性是业务事实:没支付的单就是没有支付时间。CREATE TABLE orders ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), user_id uuid NOT NULL, status integer, total_amount numeric(10,2), created_at timestamp NOT NULL, paid_at timestamp );易错金额用 float / double 会丢精度(二进制存不了 0.1),报表对不上账。钱永远 numeric / decimal。
05跑 seed.sql 的「D01」段:灌入 5 万行(里面埋了脏数据)
场景空表什么都查不了,把老板的订单灌进去。
psql -f 文件或进去之后\i 文件执行整个脚本;今天只跑 §A 段两条语句(先 INSERT 5 万行,再 UPDATE 埋脏数据)。灌完select count(*)核对行数,数据里埋着负金额、时间倒挂、空状态--都是本周的练习素材。-- 方式一:psql -f 整个文件,或编辑后只留 §A 段 -- 方式二:psql 里逐条粘贴执行 select count(*) from orders; -- 50000易错同一段 INSERT 跑两遍 = 数据翻倍(或主键冲突)。发现数字不对劲,先怀疑自己重复灌过。
练 · 65 min
- Docker 起
pg16,建库shop并连进去参考答案
psql 的元命令以反斜杠开头,只有 psql 认;CREATE DATABASE 是 SQL。
docker run -d --name pg16 -e POSTGRES_PASSWORD=dev -p 5432:5432 postgres:16 docker exec -it pg16 psql -U postgres CREATE DATABASE shop; \c shop - 建 orders 表:字段类型自己定,定完对照本页下方的结构检查
参考答案
status 可空(业务上就是有脏数据)、paid_at 可空(没支付的单没有支付时间)--可空性是业务事实,别全写 NOT NULL。
CREATE TABLE orders ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), user_id uuid NOT NULL, status integer, total_amount numeric(10,2), created_at timestamp NOT NULL, paid_at timestamp ); - 跑 seed.sql 的「D01」段灌入 5 万行
参考答案
答案不是抄 SQL,是把文件里 §A 的两条语句找出来跑掉;第 2 条 UPDATE 依赖第 1 条的结果。
-- seed.sql 的 §A 段共两条:先 INSERT 5 万行,再 UPDATE 埋 20 单时间倒挂 -- 在 psql 里逐条执行,或 psql -f 只跑这两条 -
\dt和\d orders看结构,输出贴进 notes.md参考答案
\dt 列出库里的表(此刻只有 orders);\d orders 列出字段、类型、可空性、默认值和主键。把输出贴进 notes.md。
- 开
\timing,跑select count(*) from orders,记下行数与耗时参考答案
第一次跑会几毫秒到几十毫秒(全表扫描);把行数和耗时记下来,第 6 周百万行时回来对比。
\timing on select count(*) from orders; -- 50000 行