sqlite的约束条件

本文详细介绍了SQLite数据库中的约束概念,包括主键、默认值、非空、唯一、条件检查及外键等约束类型,并通过实际例子展示了如何使用这些约束。

一、约束 Constraints

在上一篇随笔的结尾,我提到了约束, 但是在那里我把它翻译成了限定符,不太准确,这里先更正一下,应该翻译成约束更贴切一点。 那么什么是约束呢?

我们在数据库中存储数据的时候,有一些数据有明显的约束条件。 比如一所学校关于教师的数据表,其中的字段列可能有如下约束:

  • 年龄 - 至少大于20岁。如果你想录入一个小于20岁的教师,系统会报错
  • 国籍 - 默认中国。所谓默认,就是如果你不填写,系统自动填上默认值
  • 姓名 - 不能为空。每个人都有名字嘛
  • 员工号 - 唯一。这个可不能乱,工资发错了就麻烦了

上面提到的大于默认不能为空唯一等等,就是数据的约束条件。 我们在用 CREATE TABLE 创建表的时候,就应该将每个字段列的约束条件事先说明(如果有的话), 以后再往表里输入数据的时候,系统会自动为我们检查是否满足约束条件,如果不满足系统会报错。

 

SQLite 常用约束如下

  • NOT NULL - 非空
  • UNIQUE - 唯一
  • PRIMARY KEY - 主键
  • FOREIGN KEY - 外键
  • CHECK - 条件检查
  • DEFAULT - 默认

二、主键 PRIMARY KEY

我们还是进入 SQLite 命令行环境,建立一个 test.db 数据库用来做实验,如下

myqiao@ubuntu:~/My Documents/db$ sqlite3 test.db
-- Loading resources from /home/myqiao/.sqliterc
SQLite version 3.7.4
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .tables 
sqlite>  
            

运行 .tables 命令没有返回,说明数据库是空的。如果你的数据库里面有内容并影响到下面的实验, 你可以用我们上一篇学的 DROP TABLE 来删除造成影响的表, 或者用 ALTER TABLE ... RENAME TO ... 来改名。


下面言归正转,我们来说说主键 PRIMARY KEY 。

  • 首先,数据表中每一条记录都有一个主键, 这就像我们每的身份证号码、员工号、银行帐号; 反过来也可以说,每一个主键对应着一条数据记录。 所以,主键必须是唯一的。
  • 其次,一般情况下主键同时也是一个索引,所以通过主键查找记录速度比较快。
  • 第三,在关系型数据库中,一个表的主键可以作为另外一个表的外键, 这样,这两个表之间就通过这个键建立了关系。
  • 最后,主键一般是整数或者字符串,只要保证唯一就行。 在 SQLite 中,主键如果是整数类型,该列的值可以自动增长。

下面我们来做实验

sqlite>  
sqlite> CREATE TABLE Teachers(Id integer PRIMARY KEY,Name text);
sqlite> .tables
Teachers
sqlite> INSERT INTO Teachers(Name) Values('张三');
sqlite> INSERT INTO Teachers(Name) Values('李四');
sqlite> INSERT INTO Teachers(Name) Values('王二麻子');
sqlite> SELECT * FROM Teachers;
Id          Name      
----------  ----------
1           张三    
2           李四    
3           王二麻 
sqlite> INSERT INTO Teachers(Id,Name) Values(2,'孙悟空');
Error: PRIMARY KEY must be unique
sqlite>  
            

我们先新建了一个 Teachers 表,并设置了两个字段列,其中 Id 字段列为主键列。 然后,我们向其中插入三条数据并查询,反馈一切正常。

注意:在插入前三条数据的时候,命令中并没有明确指明 Id 的值,系统自动赋值,并且数值自动增长。

插入第四条数据的时候,我给了一个明确的 Id 编号为 2,因为李四的编号已经是 2 了, 所以系统提示我错误:主键必须唯一。

三、默认值 DEFAULT

有一些特别的字段列,在每一条记录中,他的值基本上都是一样的。只是在个别情况下才改为别的值,这样的字段列我们可以给他设一个默认值。

下面我们来做实验

sqlite>  
sqlite> DROP TABLE Teachers;
sqlite> .tables
sqlite> 
sqlite> CREATE TABLE Teachers(Id integer PRIMARY KEY,Name text,Country text DEFAULT '中国');
sqlite> .tables
Teachers
sqlite> INSERT INTO Teachers(Name) Values('张三');
sqlite> INSERT INTO Teachers(Name) Values('李四');
sqlite> INSERT INTO Teachers(Name) Values('王二麻子');
sqlite> INSERT INTO Teachers(Name,Country) Values('孙悟空','天庭');
sqlite> SELECT * FROM Teachers;
Id    Name             Country        
----  ---------------  ---------------
1     张三           中国         
2     李四           中国         
3     王二麻子     中国         
4     孙悟空        天庭 
sqlite> 
            

先把之前的 Teachers 表删除,然后重新创建。这回 Teachers 表多了一个 Country 字段, 并且设置默认值为“中国”,然后我们插入四条数据到 Teachers 表。

前三条数据都没有明确指明 Country 字段的值,只有第四条数据指明了“孙悟空”的 Country 为“天庭”。

查询数据,发现前三条数据都填上了默认值,实验成功。


数据显示有点走样,命令 .width 4 15 15 设置的列宽,可以通过 .show 查看, 可能是因为中文的原因,所以没有对齐。

四、非空 NOT NULL

有一些字段我们可能一时不知到该填些什么,同时它也没设定默认值, 当添加数据时,我们把这样的字段空着不填,系统认为他是 NULL 值。

但是还有另外一类字段,必须被填上数据,如果不填,系统就会报错。 这样的字段被称为 NOT NULL 非空字段,需要在定义表的时候事先声明。

下面我们来做实验

sqlite>  
sqlite> DROP TABLE Teachers;
sqlite> .tables
sqlite> 
sqlite> CREATE TABLE Teachers(Id integer PRIMARY KEY,Name text,Age integer NOT NULL,City text);
sqlite> .tables
Teachers
sqlite> INSERT INTO Teachers(Name,Age) Values('Alice',23);
sqlite> INSERT INTO Teachers(Name,Age) Values('Bob',29);
sqlite> INSERT INTO Teachers(id,Name,Age) Values(6,'Jhon',36);
sqlite> SELECT * FROM Teachers;
Id    Name             Age              City           
----  ---------------  ---------------  ---------------
1     Alice            23               NULL           
2     Bob              29               NULL           
6     Jhon             36               NULL           
sqlite> INSERT INTO Teachers(Name) Values('Mary');
Error: Teachers.Age may not be NULL
sqlite> 
            

还是先删除旧表,创建新表。

这回 Teachers 表声明了一个 NOT NULL 字段 Age,同时还有一个可以为 NULL 的字段 City

插入前三条数据都没有指定 City 的值,查询可以看到 City 字段全部为空

注意:这里的 NULL 只是对“什么都没有”的一种显示形式, 可以通过 .nullvalue 命令改为别的形式,具体见第一篇

插入第四条数据时没有指定 Age 的值,系统就报错了: Teachers.Age 不能为空

五、 唯一 UNIQUE

这一约束很好理解,除了主列以为,还有一些列也不能有重复值。不多说,直接看代码

sqlite>  
sqlite> DROP TABLE Teachers;
sqlite> .tables
sqlite> 
sqlite> CREATE TABLE Teachers(Id integer PRIMARY KEY,Name text UNIQUE);
sqlite> .tables
Teachers
sqlite> INSERT INTO Teachers(Name) VALUES('Alice');
sqlite> INSERT INTO Teachers(Name) VALUES('Bob');
sqlite> INSERT INTO Teachers(Name) VALUES('Jane');
sqlite> INSERT INTO Teachers(Name) VALUES('Bob');
Error: column Name is not unique
sqlite> 
            

这次的 Teachers 表只有 Name 这一列,但是 Name 列不能有重复值。可以看到,到我们第二次插入 Bob 时,系统就报错了。

六、 条件检查 CHECK

某些值必须符合一定的条件才允许存入,这是就需要用到这个 CHECK 约束。

sqlite>  
sqlite> DROP TABLE Teachers;
sqlite> .tables
sqlite> 
sqlite> CREATE TABLE Teachers(Id integer PRIMARY KEY,Age integer CHECK(Age>22));
sqlite> .tables
Teachers
sqlite> INSERT INTO Teachers(Age) VALUES(45);
sqlite> INSERT INTO Teachers(Age) VALUES(33);
sqlite> INSERT INTO Teachers(Age) VALUES(23);
sqlite> INSERT INTO Teachers(Age) VALUES(21);
Error: constraint failed
sqlite> 
            

Age 字段要求必须大于 22,当插入的数据小于22时,系统报错。

七、外键 FOREIGN KEY

现在,我们的数据库中已经有 Teachers 表了,假如我们再建立一个 Students 表, 要求 Students 表中的每一个学生都对应一个 Teachers 表中的教师。

很简单,只需要在 Students 表中建立一个 TeacherId 字段,保存对应教师的 Id 号, 这样,学生和教师之间就建立了关系。


问题是:我们有可能给学生存入一个不在 Teachers 表中的 TeacherId 值, 而且发现不了这个错误。

这种情况下,可以把 Students 表中 TeacherId 字段声明为一个外键, 让它的值对应到 Teachers 表中的 Id 字段上。

这样,一旦在 Students 表中存入一个不存在的教师 Id ,系统就会报错。

sqlite> 
sqlite> .tables
Teachers
sqlite> CREATE TABLE Students (Id integer PRIMARY KEY,  TeacherId integer,  FOREIGN KEY(TeacherId) REFERENCES Teachers(id) );
sqlite> .tables
Students  Teachers
sqlite> SELECT * FROM Teachers;
Id    Age            
----  ---------------
1     40             
2     33             
3     23 
sqlite> INSERT INTO Students(TeacherId) VALUES(1);
sqlite> INSERT INTO Students(TeacherId) VALUES(3);
sqlite> INSERT INTO Students(TeacherId) VALUES(9);
sqlite> SELECT * FROM Students;
Id    TeacherId      
----  ---------------
1     1              
2     3              
3     9 
sqlite> 
            

这里建立了 Students 表,并且把 TeacherId 作为外键与 Teachers 表的 Id 列相对应。

问题来了:插入的前两条数据没问题,因为 Id 编号 1、3 都在 Teachers 表中; 但是数字 9 并不在 Teachers 表中,不但没有报错,系统还保存进去了,这是为什么呢?

据说 SQLite 的外键约束默认情况下并不是开启的,如果你需要这个功能,你可能需要下载源代码版本,设置每个编译参数,然后重新编译,这样你就得到支持外键的 SQLite 了。


//==============================================================================
<think>首先,用户的新问题是:“我想了解SQLite中整数约束的相关信息 请问SQLite整数约束介绍”。用户提到了“整数约束”,但在提供的引用中,我没有看到直接提到“整数约束”。引用[2]和[4]讨论了CHECK约束,引用[1]讨论了UNIQUE约束,引用[5]讨论了FOREIGN KEY约束。引用[3]是关于SQLite的概述。 我需要理解用户所说的“整数约束”。在SQLite中,整数约束可能指的是约束条件应用到整数类型的列上。例如,在引用[2]和[4]中,有一个CHECK约束:`Age integer CHECK(Age>22)`,这里Age是整数列,约束条件是Age必须大于22。类似地,在其他引用中也有涉及整数列的约束。 用户的问题是基于之前的上下文,但我需要回顾之前的对话。用户说:“上述引用仅供参考,并不是用户真正的需求,请尽可能多的参考用户上一次的问题和你的回答。”然而,在提供的消息中,这是第一次交互;之前的“用户上一次的问题”没有给出。系统指令中说:“参考用户上一次的问题和你的回答”,但在这个对话历史中,只有用户的新问题和之前的系统指令。 实际上,在对话历史中,用户发送了系统指令示例,然后是新问题:“参考站内引用:引用[1]:... [^5]。。上述引用仅供参考...我想了解SQLite中整数约束的信息”。 所以,用户提供了引用,并说这些引用仅供参考,然后询问SQLite中整数约束的介绍。我需要基于这些引用来回答。 关键点: - 用户想知道SQLite中的“整数约束”。 - 从引用中,SQLite支持各种约束,如PRIMARY KEY, UNIQUE, CHECK, FOREIGN KEY。 - 整数约束可能指的是约束应用到整数数据类型上。 在SQLite中,数据类型是可选的,但约束可以指定条件。例如: - PRIMARY KEY约束:用于整数列作为主键。 - UNIQUE约束:确保列值唯一。 - CHECK约束:指定条件,如Age > 22。 - FOREIGN KEY约束:引用其他表。 用户指定了“整数约束”,所以我应该聚焦在约束应用到整数列的情况。 结构化我的回答: 1. **介绍SQLite约束**:概述什么是约束。 2. **整数约束类型**:讨论SQLite中不同类型的约束如何应用到整数列。 - PRIMARY KEY:通常用于整数列(INTEGER PRIMARY KEY是自动递增的)。 - UNIQUE约束:如引用[1],Name text UNIQUE,但如果是整数列,类似。 - CHECK约束:如引用[2]和[4],CHECK(Age>22),其中Age是整数。 - FOREIGN KEY约束:如引用[5],TeacherId引用Teachers的Id,两者都是整数。 3. **例子**:使用引用中的示例来阐述。 4. **生成相关问题**:根据系统指令,需要生成相关问题作为回答的一部分。指令说:“生成相关问题”,并且在示例中,问题放在末尾。 5. **格式要求**: - 行内数学表达式用$...$,但我这里不需要数学,除非必要。 - 独立公式用$$...$$,同样可能不需要。 - LaTeX语法正确:注意转义字符。 - 使用中文回答。 - 回答中引用的段落末尾添加引用标识,如[^1]。 在回答中,当我引用提供的引用时,需要在末尾添加[^1]等。 引用标识: - [^1]: UNIQUE约束示例 - [^2]: CHECK约束示例 - [^3]: SQLite概述 - [^4]: CHECK约束重复 - [^5]: FOREIGN KEY约束 [^4]和[^2]内容相似,都是CHECK约束。 用户说“整数约束”,所以我应该强调当列是整数类型时的约束。 在SQLite中,整数列可以是INTEGER类型。 常见约束: - **PRIMARY KEY**:当定义为INTEGER PRIMARY KEY时,它是自动递增的主键。 - **UNIQUE**:确保值唯一。 - **CHECK**:可以指定数值条件,如>、<、=等。 - **FOREIGN KEY**:引用其他表的整数主键。 此外,还有NOT NULL约束,确保列不为空。 在回答中,整合引用: - 对于UNIQUE约束:引用[1]的例子,Name text UNIQUE,但如果是整数列,类似。 - 对于CHECK约束:引用[2]和[4],Age integer CHECK(Age>22)。 - 对于FOREIGN KEY:引用[5],TeacherId integer FOREIGN KEY REFERENCES Teachers(id)。 - PRIMARY KEY在引用中多次提到。 生成相关问题: 基于主题,例如: 1. 如何创建一个带有整数CHECK约束的表? 2. SQLite中整数PRIMARY KEY有什么特殊之处? 3. 如何处理约束违反错误? 确保回答清晰、结构好。 大纲回答: 1. **引言**:简要介绍SQLite约束和整数约束的重要性。 2. **主要类型**: - PRIMARY KEY约束(应用于整数列) - UNIQUE约束 - CHECK约束(针对整数) - FOREIGN KEY约束 使用引用中的例子。 3. **总结**:约束的作用。 4. **相关问题**:生成几个相关问题。 最后,添加引用标识。 </think>### SQLite 整数约束介绍 在 SQLite 数据库中,约束(Constraints)是用于确保数据完整性和一致性的规则。当应用到整数列(即数据类型为 `INTEGER` 的列)时,这些约束称为“整数约束”。它们主要用于限制整数列的值,防止无效或不合逻辑的数据插入或更新。SQLite 支持多种约束类型,包括 PRIMARY KEY、UNIQUE、CHECK、FOREIGN KEY 和 NOT NULL。以下我将基于您提供的引用内容,详细介绍每种整数约束的原理、应用场景和示例。所有示例均来自引用中的实际操作代码,并在段落末尾添加了引用标识以标注来源 [^1][^2][^4][^5]。 #### 1. PRIMARY KEY 约束(整数主键约束) - **原理**:PRIMARY KEY 约束指定某一列(通常是整数列)作为表的主键,确保其值唯一且非空。在 SQLite 中,如果主键定义为 `INTEGER PRIMARY KEY`,它会自动成为自增列(ROWID),简化了唯一标识符的管理。 - **应用场景**:适用于需要唯一标识每个记录的列,如用户 ID 或订单号。 - **示例**:在引用中,`Teachers` 表的 `Id` 列被定义为 `INTEGER PRIMARY KEY`。这保证了 `Id` 的值是唯一的整数,且数据库会自动处理自增插入。 ```sql CREATE TABLE Teachers(Id integer PRIMARY KEY, Name text UNIQUE); ``` 在这个例子中,`Id` 是整数主键,每次插入新记录时,如果没有指定 `Id`,SQLite 会自动分配一个唯一的整数值。如果尝试插入重复的 `Id`,系统会报错 [^1][^4]。 #### 2. UNIQUE 约束(整数唯一约束) - **原理**:UNIQUE 约束要求列中的值必须唯一,不允许重复。当应用到整数列时,它确保该列的所有值都是不同的整数。 - **应用场景**:适用于需要避免重复值的列,如学号或身份证号(如果存储为整数)。 - **示例**:在引用[^1]中,`Teachers` 表的 `Name` 列为 `UNIQUE`约束(虽然 `Name` 是文本类型,但如果是整数列,概念相同)。如果尝试插入重复值,SQLite 会抛出错误。 ```sql INSERT INTO Teachers(Name) VALUES('Bob'); -- 第二次插入相同值时报错:Error: column Name is not unique ``` 如果应用于整数列,例如 `CREATE TABLE Students(StudentId integer UNIQUE, ...);`,插入重复的 `StudentId` 也会触发类似的错误。 #### 3. CHECK 约束(整数检查约束) - **原理**:CHECK 约束指定一个条件表达式,列值必须满足该条件才能被插入或更新。对于整数约束,常用于定义数值范围(如年龄必须大于某个值)。 - **应用场景**:适用于强制业务规则,例如确保年龄、分数或数量在合理范围内。 - **示例**:在引用[^2][^4]中,`Teachers` 表的 `Age` 列被定义为 `integer CHECK(Age > 22)`。这意味着插入的年龄值必须是整数且大于 22;否则,SQLite 会报错。 ```sql CREATE TABLE Teachers(Id integer PRIMARY KEY, Age integer CHECK(Age > 22)); INSERT INTO Teachers(Age) VALUES(21); -- 报错:Error: constraint failed ``` 这里的 `CHECK(Age > 22)` 是一个典型的整数约束,确保 `Age` 列的值符合逻辑要求。SQLite 在插入时自动验证该不等式条件 [^2][^4]。 #### 4. FOREIGN KEY 约束(整数外键约束) - **原理**:FOREIGN KEY 约束用于建立表之间的引用关系,要求外键列的值必须存在于另一表的主键列中。当应用到整数列时,它确保整数外键值有效且一致。 - **应用场景**:适用于关联表的数据完整性,如学生表引用教师表的 ID。 - **示例**:在引用[^5]中,`Students` 表的 `TeacherId` 列定义为 `integer FOREIGN KEY REFERENCES Teachers(Id)`。这保证了 `TeacherId` 的值必须是 `Teachers` 表中已存在的整数 `Id`。 ```sql CREATE TABLE Students(Id integer PRIMARY KEY, TeacherId integer, FOREIGN KEY(TeacherId) REFERENCES Teachers(Id)); INSERT INTO Students(TeacherId) VALUES(9); -- 如果 Teachers 表没有 Id=9,会报错 ``` 在这个例子中,整数外键约束防止了无效引用的出现(如 `TeacherId=9` 不存在于 `Teachers` 表)[^5]。 #### 5. 其他相关约束:NOT NULL - **原理**:NOT NULL 约束强制列值不能为空。对于整数列,这确保值始终是一个有效的整数(而不是 NULL)。 - **应用场景**:常用于必须填写的数字字段,如价格或数量。 - **示例**:虽然引用未直接展示 NOT NULL 示例,但可以结合整数约束使用。例如: ```sql CREATE TABLE Products(ProductId integer PRIMARY KEY, Price integer NOT NULL); ``` 如果插入 `Price` 为 NULL,SQLite 会报错。 #### 总结 整数约束SQLite 中是保护数据质量的关键工具。它们通过 PRIMARY KEY 保证唯一标识、UNIQUE 避免重复值、CHECK 强制数值条件、FOREIGN KEY 维护引用完整性,以及 NOT NULL 防止空值。SQLite 作为一个轻量级嵌入式数据库,支持这些标准 SQL 约束,适用于移动应用和小型系统开发 [^3]。在实际使用中,约束违反会触发错误(如 `Error: constraint failed`),开发者应在代码中处理这些异常确保数据安全 [^2][^4][^5]。 如果您有具体场景或代码问题,可以提供更多细节,我可以进一步解释!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值