MySQL中“允许NULL”仅允许插入NULL值,与空字符串''无关;插入''报错通常因字段设NOT NULL且启用STRICT模式或类型不兼容。
MySQL 中 NULL 复选框勾选后,为什么插入空字符串还是报错?
勾选了「允许 null」,但执行 insert into table (col) values (''); 仍可能失败,根本原因在于:「允许 null」只影响 null 值的插入,和空字符串 '' 完全无关。两者在 mysql 中类型不同、语义不同、校验时机也不同。
常见错误现象:Column 'col' cannot be null 错误其实不是因为没填值,而是你试图插入 NULL,但该字段被意外设成了 NOT NULL;反过来,插入 '' 报错,则大概率是字段加了 NOT NULL + STRICT_TRANS_TABLES 模式,或触发了 NOT NULL 约束下的隐式转换拦截。
- 勾选 NULL → 实际生成的是
col VARCHAR(255) NULL,允许显式写入NULL - 不勾选 NULL → 默认加
NOT NULL,此时若没设默认值,又没传值,就会报错 - 空字符串
''是合法非 NULL 值,能否插入取决于字段类型是否接受它(如INT类型会转成0或报错,VARCHAR通常可以) - 如果同时设了
DEFAULT '',那不传值时会自动补空字符串,而不是NULL
PostgreSQL 的 ALTER COLUMN ... DROP NOT NULL 和默认值冲突怎么解?
想把一个已有数据的字段改成允许 NULL,直接 ALTER TABLE t ALTER COLUMN c DROP NOT NULL 能成功,但后续插入 NULL 仍可能被默认值“拦截”——因为默认值还在,且某些 ORM 或客户端会主动代填默认值,掩盖了 NULL 意图。
使用场景:迁移旧表、兼容新业务逻辑、修复历史设计缺陷。关键点在于,默认值和 NULL 权限是正交控制项,删了 NOT NULL 不等于清除了默认行为。
- 先确认当前默认值:
SELECT column_default FROM pg_attrdef d JOIN pg_attribute a ON d.adnum = a.attnum WHERE a.attrelid = 'table_name'::regclass AND a.attname = 'col_name'; - 如需彻底放开,应同步清除默认值:
ALTER TABLE t ALTER COLUMN c DROP DEFAULT; - 如果保留默认值(比如为了新行兜底),又想让应用能显式写
NULL,那就别动默认值,只要确保应用层发送的是字面量NULL,而非空字符串或未传字段 - 注意:某些 PostgreSQL 驱动(如 psycopg2)对空字符串和
None的映射有差异,None才对应 SQLNULL,''仍是字符串
SQLite 的 DEFAULT NULL 其实是无效语法,该怎么写才真允许空?
SQLite 不支持 DEFAULT NULL 写法,写上去不会报错,但实际会被忽略——字段依然按 NOT NULL 行为处理(除非显式声明 NULL)。这是 SQLite 的冷知识,也是很多轻量项目踩坑源头。
参数差异明显:INTEGER NULL DEFAULT 0 和 INTEGER DEFAULT 0 在 SQLite 中等价;但 TEXT NULL 和 TEXT NULL DEFAULT NULL 是两回事——后者语法错误,前者才真正开启 NULL 接受能力。
- 正确写法只有两种:
col TEXT NULL(允许 NULL,无默认)或col TEXT DEFAULT ''(不允许 NULL,但默认为空字符串) - 想实现“可空 + 有默认”,只能靠应用层判断:插入时显式传
NULL或留空,不依赖数据库兜底 - SQLite 的
NOT NULL约束在INSERT时检查,但不会阻止你插''或0,这点和 MySQL/PG 不同,容易误判约束是否生效 - 用
PRAGMA table_info(table_name)查看字段的notnull列:0 表示允许 NULL,1 表示 NOT NULL
Django Model 字段设 null=True 后,迁移没生效?
写了 models.CharField(null=True, blank=True),跑完 python manage.py makemigrations 却没生成任何 SQL,或者生成了但字段在 DB 里仍是 NOT NULL——大概率是因为没运行 migrate,或迁移被跳过,或字段已有非 NULL 数据但没提供 default / blank 处理策略。
性能影响很小,但逻辑错位后果严重:Django 层认为可空,DB 层拦着不让插 NULL,结果抛出 IntegrityError。
- 必须执行
python manage.py migrate,仅makemigrations不会改库 - 如果字段已有数据,添加
null=True时,Django 会要求你选择:提供默认值(用于填充老数据),或中止(quit) -
blank=True只影响 Django 表单校验,和数据库完全无关;null=True才控制 DB 的NULL属性 - SQLite 用户注意:Django 迁移会自动加
NULL,但不会删已有的NOT NULL(因 SQLite 不支持DROP NOT NULL),此时需手动ALTER TABLE或重建表










