SQLite 约束 (Constraints) 面试核心知识点

目录

[1. 什么是数据库约束?](#1. 什么是数据库约束?)

[2. SQLite 中的主要约束类型](#2. SQLite 中的主要约束类型)

[3. 约束详解与面试重点](#3. 约束详解与面试重点)

[3.1 PRIMARY KEY (主键约束)](#3.1 PRIMARY KEY (主键约束))

[3.2 NOT NULL (非空约束)](#3.2 NOT NULL (非空约束))

[3.3 UNIQUE (唯一约束)](#3.3 UNIQUE (唯一约束))

[3.4 FOREIGN KEY (外键约束)](#3.4 FOREIGN KEY (外键约束))

[3.5 CHECK (检查约束)](#3.5 CHECK (检查约束))

[3.6 DEFAULT (默认值约束)](#3.6 DEFAULT (默认值约束))

[4. 约束的定义级别](#4. 约束的定义级别)


1. 什么是数据库约束?

面试官提问: "你能谈谈什么是数据库约束吗?为什么我们要使用它?"

回答要点:

数据库约束(Constraints)是在表的数据列上强制执行的规则 。它们的主要目的是保证数据的完整性、准确性和可靠性

  • 目的:

    • 限制可以存储到表中的数据类型。

    • 防止无效或"脏"数据进入数据库。

    • 维护表与表之间的关系(参照完整性)。

  • 执行时机: 约束会在数据发生变化时(如 INSERT, UPDATE, DELETE)自动检查。如果操作违反了约束,该操作将被拒绝并报错。

2. SQLite 中的主要约束类型

SQLite 支持以下几种主要的约束:

  1. PRIMARY KEY (主键)

  2. NOT NULL (非空)

  3. UNIQUE (唯一)

  4. FOREIGN KEY (外键)

  5. CHECK (检查)

  6. DEFAULT (默认值)

3. 约束详解与面试重点

3.1 PRIMARY KEY (主键约束)

  • 定义: 用于唯一标识表中的每一行。

  • 特性:

    1. 隐含了 UNIQUENOT NULL 两个约束。

    2. 一张表最多只能有一个主键。

    3. 主键可以是单列,也可以是多列(称为"复合主键")。

  • 示例:

    复制代码
    -- 单列主键
    CREATE TABLE Users (
        user_id INTEGER PRIMARY KEY, -- 隐含 UNIQUE 和 NOT NULL
        username TEXT
    );
    
    -- 复合主键 (表级定义)
    CREATE TABLE OrderDetails (
        order_id INTEGER,
        product_id INTEGER,
        quantity INTEGER,
        PRIMARY KEY (order_id, product_id)
    );
  • ⭐ SQLite 面试重点:INTEGER PRIMARY KEYROWID

    • 在 SQLite 中,几乎所有的表都有一个隐藏的、唯一的64位有符号整数列,名为 ROWID

    • 如果你将一列定义为 INTEGER PRIMARY KEY(必须是 INTEGER,不能是 INTBIGINT),那么这一列实际上会成为 ROWID 的别名。

    • 好处: 这是 SQLite 中最高效的主键类型,因为它直接使用了底层的 ROWID 进行查找,速度极快。

    • 对比: 如果你定义 user_id TEXT PRIMARY KEY,SQLite 会为 user_id 单独创建一个索引,并且仍然在内部维护一个 ROWID

  • ⭐ SQLite 面试重点:AUTOINCREMENT 关键字

    • 误区: 很多人认为 INTEGER PRIMARY KEY 就会自动增长。它确实会自动生成一个唯一的 ID,但它可能重用之前删除过的行的 ID。

    • AUTOINCREMENT 的真正作用: 当你使用 INTEGER PRIMARY KEY AUTOINCREMENT 时,SQLite 会保证 新插入的 ID 永远大于 该表中曾经存在过的任何 ID。即使你删除了 ID 最大的行,下一个 ID 也会继续增长,绝不重用

    • 代价: AUTOINCREMENT 会带来额外的 CPU、内存和磁盘开销,因为它需要一个额外的 sqlite_sequence 表来跟踪每个表的最大 ID。

    • 面试结论: 除非你明确需要"ID 永不重用"的特性,否则只使用 INTEGER PRIMARY KEY 是最高效的选择。

      -- 推荐的高效方式 (可能会重用已删除的ID)
      CREATE TABLE Logs (
      log_id INTEGER PRIMARY KEY,
      message TEXT
      );

      -- 保证ID永不重用 (开销稍大)
      CREATE TABLE Invoices (
      invoice_id INTEGER PRIMARY KEY AUTOINCREMENT,
      amount REAL
      );

3.2 NOT NULL (非空约束)

  • 定义: 确保该列的值永远不能为 NULL

  • 示例:

    复制代码
    CREATE TABLE Products (
        product_id INTEGER PRIMARY KEY,
        name TEXT NOT NULL, -- 商品名不能为空
        price REAL NOT NULL   -- 价格不能为空
    );
    
    -- 尝试插入 NULL 将会失败
    INSERT INTO Products (name, price) VALUES (NULL, 9.99); -- 错误!

3.3 UNIQUE (唯一约束)

  • 定义: 确保该列(或多列组合)中的所有值都是唯一的。

  • 特性:

    • PRIMARY KEY 类似,但 UNIQUE 约束允许 NULL

    • ⭐ SQLite 面试重点:UNIQUE 约束的列中,你可以存储多个 NULL 。SQLite (以及 PostgreSQL) 认为 NULL 不等于 NULL,所以多个 NULL 并不违反唯一性。 (注意:这在 SQL Server 或 Oracle 中行为不同)。

    • 一张表可以有多个 UNIQUE 约束。

  • 示例:

    复制代码
    CREATE TABLE Employees (
        emp_id INTEGER PRIMARY KEY,
        ssn TEXT UNIQUE,      -- 社保号必须唯一 (但允许有人没有社保号, 即 NULL)
        email TEXT UNIQUE     -- 邮箱也必须唯一
    );
    
    -- 以下插入在 SQLite 中是允许的
    INSERT INTO Employees (ssn) VALUES (NULL);
    INSERT INTO Employees (ssn) VALUES (NULL); -- 再次插入 NULL,仍然允许

3.4 FOREIGN KEY (外键约束)

  • 定义: 用于在两个表之间建立连接并强制实现参照完整性

  • 工作原理:

    • 它指定一个(或一组)列,称为"子列",其值必须在另一张表("父表")的 PRIMARY KEYUNIQUE 列中存在,或者为 NULL
  • 示例:

    复制代码
    -- 1. 创建父表 (Departments)
    CREATE TABLE Departments (
        dept_id INTEGER PRIMARY KEY,
        dept_name TEXT NOT NULL
    );
    
    -- 2. 创建子表 (Employees)
    CREATE TABLE Employees (
        emp_id INTEGER PRIMARY KEY,
        name TEXT,
        dept_id INTEGER, -- 这是外键列
        FOREIGN KEY (dept_id) REFERENCES Departments (dept_id)
            ON DELETE SET NULL  -- 如果父表部门被删除,员工的部门设为NULL
            ON UPDATE CASCADE -- 如果父表部门ID更新,员工的部门ID也跟着更新
    );
  • 外键动作 (ON DELETE / ON UPDATE):

    • NO ACTION / RESTRICT (默认):如果子表存在关联数据,禁止删除/更新父表。

    • SET NULL:父表数据变化时,子表对应列设为 NULL

    • SET DEFAULT:父表数据变化时,子表对应列设为默认值。

    • CASCADE:父表数据删除/更新时,子表关联的行也级联删除/更新

  • ⭐ SQLite 面试重点:启用外键

    • 在旧版本的 SQLite 中,外键支持默认是关闭的。在现代版本中(3.6.19 之后),通常在编译时默认开启。

    • 但为了保证兼容性和安全性,在建立连接后立即执行 PRAGMA foreign_keys = ON; 是一个非常好的习惯,这在面试中是加分项

      -- 在你的应用程序连接数据库后,应首先执行这个命令
      PRAGMA foreign_keys = ON;

3.5 CHECK (检查约束)

  • 定义: 允许你指定一个布尔表达式,INSERTUPDATE 的数据必须满足该表达式(即表达式结果为 TRUE)才能被写入。

  • 特性: SQLite 支持 CHECK 约束(但 MySQL 长期忽略它,直到 8.0)。

  • 示例:

    复制代码
    CREATE TABLE Products (
        id INTEGER PRIMARY KEY,
        name TEXT,
        price REAL CHECK (price > 0), -- 价格必须大于0
        discount REAL,
        -- 表级 CHECK 约束,可以引用多列
        CHECK (discount < price) -- 折扣必须小于价格
    );

3.6 DEFAULT (默认值约束)

  • 定义:INSERT 语句没有为该列提供值时,自动为其分配一个默认值。

  • 示例:

    复制代码
    CREATE TABLE Orders (
        order_id INTEGER PRIMARY KEY,
        order_date TEXT DEFAULT (DATE('now')), -- 使用函数作为默认值
        status TEXT DEFAULT 'Pending'          -- 使用常量作为默认值
    );
    
    -- 插入时,可以不指定 order_date 和 status
    INSERT INTO Orders (order_id) VALUES (101);
    -- 数据库中该行将自动填充 (..., '2025-10-29', 'Pending')

4. 约束的定义级别

约束可以在两个级别上定义:

  1. 列级约束 (Column-level):

    • 作为列定义的一部分。

    • NOT NULL 只能在列级定义。

    • 适用于:NOT NULL, PRIMARY KEY, UNIQUE, CHECK, DEFAULT, FOREIGN KEY (单列)。

      CREATE TABLE Example (
      id INTEGER PRIMARY KEY,
      email TEXT UNIQUE NOT NULL CHECK (length(email) > 5)
      );

  2. 表级约束 (Table-level):

    • 在所有列定义之后,单独定义。

    • 必须用于定义"复合主键"或"复合唯一/外键" (即约束涉及多于一列)。

    • 适用于:PRIMARY KEY, UNIQUE, CHECK, FOREIGN KEY

      CREATE TABLE Example (
      col1 INTEGER,
      col2 INTEGER,
      col3 TEXT,

      复制代码
        -- 表级定义
        PRIMARY KEY (col1, col2),
        UNIQUE (col2, col3)

      );

相关推荐
Scott9999HH3 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
腻害兔3 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社4 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海4 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖5 小时前
JDK 26 新特性详解
java·开发语言
马优晨6 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区7 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大8 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai8 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
维天说8 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json