📄 一句话概括
DATE 只存日期(年-月-日),DATETIME 日期带时刻(年-月-日 时:分:秒)——日期要用专门的日期类型存,别用字符串凑合,否则比较先后、算间隔全得靠人肉。
📝 本节和前面几节的关系
4-2 数字、4-3 文字,本节是类型家族的第三族:时间。第三章建表时没放日期列,本节补上——订单表、考勤表都离不开它。核心收获:为什么字符串存日期是个坑。
一、两个类型管两种精度
| 类型 | 格式 | 例 |
|---|---|---|
DATE |
年-月-日 | 2026-09-24 |
DATETIME |
年-月-日 时:分:秒 | 2026-09-24 08:57:12 |
(MySQL 还有 TIMESTAMP 带时区转换,本课点到为止。)
二、写入:字符串样式的「日期字面量」
写进去的时候长得像字符串(要加引号),但数据库会先检查它是不是合法日期:
INSERT INTO orders (created_at) VALUES ('2026-09-24 08:57:12'); -- 合法
INSERT INTO orders (created_at) VALUES ('2026-13-01'); -- 13 月?报错拦下
这就是 4-1「第一道防线」的又一例:字符串里塞 13 月 不会被察觉,日期类型一眼识破。
三、日期类型的真正威力:会算日期的列
日期类型天生支持:
- 比先后:
WHERE created_at >= '2026-09-01' - 算间隔:两个日期相减得天数
- 按月汇总:按
DATE(created_at)分组统计
这些用字符串存都做不到(字符串比大小会得出 2026-9-1 > 2026-10-1 的荒谬结果——逐字符比较,9 > 1)。
四、动手 Demo:日期算术
CREATE TABLE orders (
id INT,
created_at DATE
);
INSERT INTO orders VALUES (1, '2026-09-20');
INSERT INTO orders VALUES (2, '2026-09-24');
-- 1. 比先后:查 9 月 22 日以后的订单
SELECT * FROM orders WHERE created_at >= '2026-09-22';
-- 2. 算间隔:订单 1 是几天前的事
SELECT julianday('2026-09-24') - julianday('2026-09-20') AS 间隔天数;
第二条查询返回 4——日期类型自己会算账。(julianday 是 SQLite 的写法,MySQL 用 DATEDIFF('2026-09-24','2026-09-20')。)
五、30 秒实验
建 d VARCHAR(20) 表,塞 2026-9-1 和 2026-10-1,执行 SELECT MAX(d)——字符串比较会告诉你「9 月 > 10 月」。再把列改成 DATE 重试,结果立刻正常。一个类型,天壤之别。
六、常见误区
- 「日期存字符串也一样」:比不了先后、算不了间隔、拦不住
13 月;三连败 - 「只要带日期就行,DATE 和 DATETIME 随便选」:只关心「哪天」用
DATE(省空间);要精确到秒的操作日志、下单时间用DATETIME
自测三问
1. DATE 和 DATETIME 差在哪?(DATETIME 多存时分秒) 2. 为什么不用字符串存日期?(无法正确比先后/算间隔/校验合法性) 3. `2026-13-01` 塞进 DATE 列会怎样?(报错拦下——类型检查生效)- ☐ 下一节(4-5 BOOLEAN-仅处理两种值的数据类型)
相关笔记
- CHAR、VARCHAR、TEXT-处理字符串的数据类型 —— 上一节:字符串家族
- WHERE、=、AND、OR-缩小范围查找符合条件的记录 —— 对日期列做范围过滤
- 🗄️ 数据库基础 · 索引 —— 全课路线图