MySQL问题,设置为不允许为空的字段却可以为空

本文详细解释了数据库中的NULL值概念,包括其与字符的区别、如何正确地在SQL语句中使用NULL值进行查询,以及在数据库操作中NULL值的一些特殊行为。
部署运行你感兴趣的模型镜像

所谓的NULL就是什么都没有,连\0都没有,\0在字符串中是结束符,但是在物理内存是占空间的,等于一个字节,而NULL就是连这一个字节都没有。在数据库里是严格区分的,任何数跟NULL进行运算都是NULL, 判断值是否等于NULL,不能简单用=,而要用IS关键字, Mysql3.23.0或以后支持用<=>用来比较两个NULL值是否相等, 即 select * from table where id <=> NULL.

为什么会出现NULL?这是来源于数据库的左右连接,不是凭空想出来的。比如:
A(ID, Name), B(ID, Address)
1, Name1 1, Shanghai
2, Name2 3, Beijing

当A左连接B则得到:
1, Name1, Shanghai
2, Name2, NULL

当A右连接B则得到:
1, Name1, Shanghai
3, NULL, Beijing

数据库的字段ID设为NOT NULL, 仅仅说明该字段不能为NULL, 也就是说只有在
INSERT INTO table(ID) VALUES(NULL);
这种情况下数据库会报错,而
INSERT INTO table(ID) VALUES(”);
这不能说明是NULL, 数据库系统会根据ID设的缺省值填充,或者如果是自增字段就自动加一
等缺省操作。

摘自:
http://bbs.youkuaiyun.com/topics/90102550

您可能感兴趣的与本文相关的镜像

Anything-LLM

Anything-LLM

AI应用

AnythingLLM是一个全栈应用程序,可以使用商用或开源的LLM/嵌入器/语义向量数据库模型,帮助用户在本地或云端搭建个性化的聊天机器人系统,且无需复杂设置

<think>我们正在讨论数据库设计中字段设置为非的常见场景。根据引用内容,我们可以总结以下几点: 1. 主键字段必须非(引用[1]强调主键的非性) 2. 业务逻辑上必须存在的字段(如订单表中的金额字段、用户表中的用户名字段) 3. 需要建立索引的字段(引用[4][5]提到可为NULL的列会使索引更复杂且占用更多存储间) 4. 外键字段(虽然理论上可为,但实际业务中通常要求非以保证参照完整性) 5. 有默认值且业务意义明确的字段(如状态字段字符串可能如默认值明确) 具体场景分析如下: ### 一、主键字段(Primary Key Fields) 根据引用[1],主键必须满足**非性**要求: > "主键字段允许(NULL)。每一行都必须有一个有效的主键值。" 因此,所有主键字段都必须设置为`NOT NULL`。这是关系数据库的基本要求。 ### 二、业务关键字段(Business Critical Fields) 在业务逻辑中必须存在的字段应设为非,例如: - **用户表**:`用户名`、`手机号`(用于登录/验证) - **订单表**:`订单金额`、`下单时间`、`订单状态` - **商品表**:`商品名称`、`商品价格` 这些字段如果为会导致业务逻辑无法正常运行。 ### 三、需要建立索引的字段(Indexed Fields) 引用[4][5]指出: > "可为NULL的列会使用更多的存储间,在MySql里也需要特殊处理。当可为NULL的列被索引时,每个索引记录需要一个额外的字节。" 因此,对于需要高频查询的字段(如商品名称、用户手机号),建议: 1. 设置为`NOT NULL` 2. 再创建索引 以提高索引效率并减少存储间。 ### 四、有默认值的字段(Fields with Default Values) 引用[2]中的问题: > "插入一条数据记录时,score字段值为(''),那这时score的字段值为''还是默认值?" 答案取决于具体定义: - 如果字段定义为`NOT NULL DEFAULT 0`,插入时显式赋值为`''`会报错(类型匹配) - 如果定义为`DEFAULT 0`且允许NULL,插入`''`可能被转换为0(取决于数据库类型转换规则) 但最佳实践是: 1. **重要字段**:设为`NOT NULL`并指定默认值(如`status INT NOT NULL DEFAULT 0`) 2. **避免歧义**:允许插入字符串(`''`)代替NULL ### 五、外键字段(Foreign Key Fields) 虽然外键在技术上允许为NULL(表示"无关联"),但在大多数业务场景中: - **强制关联场景**:如订单中的`user_id`必须非(每个订单必须属于一个用户) - **可选关联场景**:如员工表中的`manager_id`可为(表示最高管理者无上级) 建议: ```sql -- 强制关联的外键 ALTER TABLE orders ADD CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE NOT DEFERRABLE; ``` ### 六、代码可读性与维护性 设为`NOT NULL`还能带来以下好处: 1. **减少代码复杂度**:应用层无需频繁检查`if field is None` 2. **避免值陷阱**:如SQL中`WHERE field = 1`会匹配到`NULL`值 3. **统一数据语义**:字符串、0、NULL在数据库中有同处理,非字段可规避此类问题 --- ### 非设置决策流程图 ```mermaid graph TD A[需要设计字段X] --> B{X是否为业务必需?} B -->|是| C[设为NOT NULL] B -->|否| D{是否计划建索引?} D -->|是| C D -->|否| E{是否外键?} E -->|是且强制关联| C E -->|否| F[允许NULL] ``` --- ### 示例场景 #### 用户表(`users`) | 字段名 | 类型 | 非? | 理由 | |--------------|--------------|-------|--------------------------| | id | BIGINT | 是 | 主键 | | username | VARCHAR(50) | 是 | 业务唯一标识(登录用) | | phone | VARCHAR(20) | 是 | 验证必需 | | email | VARCHAR(100) | 否 | 部分用户可能无邮箱 | | created_time | TIMESTAMP | 是 | 记录创建时间必须有值 | #### 订单表(`orders`) | 字段名 | 类型 | 非? | 理由 | |--------------|-------------|-------|--------------------------| | id | VARCHAR(32) | 是 | 订单号主键 | | user_id | BIGINT | 是 | 必须关联用户 | | amount | DECIMAL(10,2)| 是 | 订单金额可缺失 | | status | SMALLINT | 是 | 状态明确(默认0待支付) | --- §§相关问题§§ 1. 如何在已有表中将允许NULL的字段改为NOT NULL? 2. 数据库设计中如何处理历史数据导致的非约束冲突? 3. 所有字段都设为NOT NULL是否合理? 4. 如何为NOT NULL字段选择合适的默认值? [^1]: 主键设计原则包括唯一性、非性、稳定性等 [^2]: 非字段插入字符串时的行为取决于数据库实现 [^3]: 允许NULL的字段需要额外的存储间 [^4]: 可为NULL的列使索引更复杂 [^5]: 在索引列上尽量避免NULL值</think>### 数据库设计中需要设置为非的常见字段类型 根据数据库设计规范和最佳实践,以下字段通常需要设置为 `NOT NULL`: #### 1. **主键字段(Primary Key)** [^1] - **原因**:主键必须唯一标识每行数据允许 - **示例**: ```sql CREATE TABLE users ( id SERIAL PRIMARY KEY NOT NULL, -- 主键必须非 username VARCHAR(50) NOT NULL ); ``` #### 2. **业务关键字段(Business Critical Fields)** - **原因**:保证核心业务数据的完整性 - **常见场景**: - 用户表:`手机号`、`邮箱`(登录凭证) - 订单表:`订单金额`、`下单时间` - 商品表:`商品名称`、`商品价格` - 支付表:`支付状态`、`交易流水号` #### 3. **外键字段(Foreign Keys)**[^1] - **原因**:维护数据引用完整性 - **示例**: ```sql CREATE TABLE orders ( order_id SERIAL PRIMARY KEY, user_id INT NOT NULL REFERENCES users(id) -- 强制关联必须存在 ); ``` #### 4. **状态标识字段(Status Flags)** - **原因**:避免业务逻辑出现未定义状态 - **示例**: ```sql CREATE TABLE tasks ( task_id SERIAL PRIMARY KEY, status VARCHAR(20) NOT NULL CHECK (status IN ('pending', 'processing', 'completed')) ); ``` #### 5. **审计字段(Audit Columns)** - **原因**:确保可追溯性 - **常见字段**: ```sql created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ``` #### 6. **需要索引的字段(Indexed Columns)**[^4][^5] - **原因**:`NULL`值会降低索引效率,增加存储开销 - **优化建议**: - 对高频查询字段(如`phone`、`email`)设为`NOT NULL` - 索引列设为`NOT NULL`可减少30%的索引存储间[^4] #### 7. **数值计算字段(Numerical Calculation Fields)** - **原因**:避免聚合计算错误 - **示例**: ```sql CREATE TABLE sales ( quantity INT NOT NULL CHECK (quantity > 0), unit_price DECIMAL(10,2) NOT NULL ); ``` ### 设置为非的技术优势[^3][^4][^5] 1. **存储优化**: - 每个`NULL`字段需额外1字节存储(NULL值列表) - 固定长度类型(如INT)存储`NULL`仍需全间占用 2. **查询性能提升**: ```sql -- NOT NULL字段的查询更高效 SELECT * FROM users WHERE phone IS NOT NULL; -- 无需检查NULL状态 ``` 3. **索引效率**: - MyISAM中可为NULL字段会使固定大小索引变为可变大小[^4] - InnoDB每个NULL索引需额外1字节存储[^5] 4. **开发简化**: - 避免应用层频繁检查`if field is null` - 消除`NULL`与字符串(`''`)的歧义[^2] ### 非设计决策流程图 ```mermaid graph TD A[新字段设计] --> B{是否业务必需?} B -->|是| C[设为NOT NULL] B -->|否| D{是否用于查询条件?} D -->|是| E[考虑NOT NULL] D -->|否| F{是否外键?} F -->|是| C F -->|否| G[允许NULL] C --> H[添加默认值 DEFAULT] ``` ### 典型示例 ```sql CREATE TABLE employees ( emp_id SERIAL PRIMARY KEY NOT NULL, national_id CHAR(18) NOT NULL UNIQUE, -- 唯一业务标识 full_name VARCHAR(100) NOT NULL, dept_id INT NOT NULL REFERENCES departments(dept_id), salary DECIMAL(12,2) NOT NULL CHECK (salary > 0), hire_date DATE NOT NULL DEFAULT CURRENT_DATE, status VARCHAR(10) NOT NULL DEFAULT 'active' ); ``` > **注意**:根据引用[5],当历史数据已存在`NULL`值时,修改为`NOT NULL`需谨慎: > 1. 先清理现有`NULL`值(填充默认值) > 2. 分阶段执行:添加新列→迁移数据→删除旧列 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值