与 select 命令相比,用于修改数据库的语句很容易理解和使用。有 3 个 DML 语句用于修改数据——insert、update 和 delete,不过它们远比字面含义看起来做的事情要多。
插入数据
使用 insert 命令向表中插入记录。insert 在单表上工作,使用 insert 命令可以一次插入一条记录,使用 select 命令可以一次插入多条记录。insert 语句的一般格式为:
1 | insert into table (column_list) values (value_list); |
变量 table 指明数据库插入到哪个表中。变量 column_list 是用逗号分隔的字段名称,这些字段必须是表中存在的。变量 value_list 是用逗号分隔的值列表,这些值与 column_list 中的字段一一对应。
插入一行
例如,下列语句向 FOODS 表插入数据:
1 | INSERT INTO FOODS (NAME, TYPE_ID) VALUES ('香蕉', 1); |
该语句插入一行,指定两列值:’香蕉’———第一个值,对应字段列表中的第一个字段 NAME;类似地,1 对应 TYPE_ID,就是第二个字段。注意,其中没有 ID 字段。本例中,数据库使用默认值。因为 ID 是整型主键,它会自动产生相关的新值。可以用简单的 select 命令验证一下,也可以查询到 ID 值。
1 | SELECT * FROM FOODS WHERE NAME='香蕉'; |
1 | SELECT MAX(ID) FROM FOODS; |
1 | SELECT LAST_INSERT_ROWID(); |
注意:值 10 是为 ID 字段自动产生的,它也是该字段的最大值。SQLite 提供单增长值,你可以使用 SQLite 内建的 LAST_INSERT_ROWID() 验证这一点,该函数返回最后一个子增长值,如示例所示。
如果在 insert 语句中为表的所有字段提供值,可以省略字段列表。本例中,假定数据库值的顺序与字段在 CREATE TABLE 语句的顺序一一对应,例如:
1 | INSERT INTO FOODS VALUES(NULL, '柚子', 1); |
注意参数的顺序,’柚子’ 在 1 的前面,这是因为创建表的方式如下。
1 | CREATE TABLE FOODS(ID INTEGER PRIMARY KEY, NAME TEXT, TYPE_ID INTEGER); |
第一个是 ID,紧接着是 NAME,最后是 TYPE_ID。因此,这也是 insert 语句中的值列表顺序。为什么在 insert 语句中为 ID 赋值 NULL?SQLite 知道 FOODS 表中的 ID 字段是自增长字段,并指定 NULL 表示不提供值。不指定值会自动触发子增长值的产生,这样做是为了方便,没有更深的含义或者理论。
插入一组行
子查询可以用在 insert 语句中,既可以作为值列表的一部分,也可以完全替代整个值列表。指定子查询为值列表时,实际上是在插入一组行,因为子查询返回的通常是一组行。下面的例子只产生一行值:
1 | INSERT INTO FOODS VALUES(NULL, '榴莲', (SELECT ID FROM TYPES WHERE NAME='水果')); |
这里不用硬编码输入 TYPE_ID,而是用 SQLite 来查询,例如:
1 | INSERT INTO FOODS |
本例使用 select 语句完全替代了值列表。只要 select 子句的字段数目与要插入的表的字段数目匹配,或者与提供的字段列表匹配,insert 语句就可以正常工作。上面的例子中,添加另一种桔子,使用 LAST_INSERT_ROWID()+1 作为 ID 字段的值,可以使用 NULL 代替。事实上,应该使用 NULL,而不是 LAST_INSERT_ROWID(),因为如果之前会话中没有插入行,LAST_INSERT_ROWID() 会返回 0。本例中的 LAST_INSERT_ROWID() 可以正常工作,但是最好不要在程序中这样做。
插入多行
使用 select 形式的 insert 可以一次插入多行。只要字段匹配,insert 可以插入结果集的所有行,例如:
1 | CREATE TABLE FOODS_BAK(ID INTEGER PRIMARY KEY, NAME TEXT, TYPE_ID INTEGER); |
上述语句表示创建一个新表 FOODS_BAK,并插入表 FOODS 的所有记录。
然而,有一种更方便的方式创建和插入表。create table 语句有特殊的语法,可以直接指定从 select 语句中创建表。前面的例子可以用下面的语法一步完成:
1 | CREATE TABLE FOODS_BAK AS SELECT * FROM FOODS; |
create table 与从 FOODS 表选择数据插入表两步并未一步。这对于创建临时表特别有用。
1 | CREATE TEMP TABLE LIST AS |
使用 create table 的这种形式时,要意识到源表的任何约束是否定义在新表中。特别是,自增长字段不会在新表中创建,索引也不会创建,UNIQUE 约束等都不会创建。许多其他数据库称这种功能为 CTAS(即 Create Table As Select 首字母的组合),但是 CTAS 不是 SQLite 用户普遍使用的称呼。
有一点值得注意,插入行时的 UNIQUE 约束。也就是说,如果在定义为 UNIQUE 的字段中插入重复值,SQLite 会停止并报错。
更新记录
update 命令用于更新表中的记录,该命令可以修改一个表中一行或多行中的一个或多个字段。update 语句的一般格式为:
1 | update table set update_list where predicate; |
update_list 是一个或多个“字段赋值”的列表,字段赋值的格式为 column_name=value。where 子句的用法与 select 语句相同,实际上,update 语句的一半都是 select 语句。where 子句使用断言识别要修改的行,然后将更新列应用到这些行,例如:
1 | UPDATE FOODS SET NAME='毛桃' WHERE NAME='桔子'; |
update 命令非常简单直接,它有很多扩展。正如 insert 语句一样,必须注意 unique 约束,因为也可能停止更新。
删除记录
使用 delete 命令可以删除表中的记录。delete 语句的一般格式为:
1 | delete from table where predicate; |
同样,delete 与 update 有些类似。就如同从 update 语句中移出了 set 部分,然后将 update 替换成 delete。where 子句的用法与 select 语句相同,只是在 delete 语句中,where 是用来确定需要被删除的记录。如:
1 | DELETE FROM FOODS WHERE NAME='苹果'; |