概述
本篇文章结构如下:
- INSERT
- UPDATE
- DELETE
- 约束
一、INSERT
INSERT 用于将行插入(或添加)到数据库表中。INSERT 的一般形式如下所示:
INSERT INTO table_name (column_list) VALUES (value_list);
其中 column_list 部分并不是必须的。插入共有以下三种方式:
- 插入完整的行;
- 插入行的一部分;
- 插入某些查询的结果。
1. 插入完整的行
我们这里以插入 Customers 表为例,首先通过 .schema 命令查看它的 CREATE 语句:
sqlite> .schema Customers
CREATE TABLE Customers
(
cust_id char(10) NOT NULL ,
cust_name char(50) NOT NULL ,
cust_address char(50) NULL ,
cust_city char(50) NULL ,
cust_state char(5) NULL ,
cust_zip char(10) NULL ,
cust_country char(50) NULL ,
cust_contact char(50) NULL ,
cust_email char(255) NULL ,
PRIMARY KEY (cust_id)
);
可以看到它总共有9个字段,其中 cust_id 是它的主键。插入完整的行如下所示:
INSERT INTO Customers
VALUES ( '1000000006',
'Toy Land',
'123 Any Street',
'New York',
'NY',
'11111',
'USA',
NULL,
NULL);
这条语句将一个新顾客插入到了 Customers 表中。存储到表中每一列数据在 VALUES 子句中给出,必须给每一列提供一个值。如果某列没有值并且允许为空的话,填入 NULL 即可。各列必须以它们在表中定义中出现的次序填充。
这种省略 column_list 的语法虽然很简单,但是并不安全,它高度依赖表中列的定义次序,如果某一时刻表结构发生了变化,那么它的插入就会失败,我们应当尽量以下面的形式插入数据:
INSERT INTO Customers
( cust_id,
cust_name,
cust_address,
cust_city,
cust_state,
cust_zip,
cust_country,
cust_contact,
cust_email)
VALUES ( '1000000006',
'Toy Land',
'123 Any Street',
'New York',
'NY',
'11111',
'USA',
NULL,
NULL);
这种写法虽然很繁琐,但是由于不依赖表中列定义次序的关系,它会更加安全。
2. 插入行的一部分
使用 INSERT 的推荐方法是明确给出 column_list,同时这也意味着我们可以省略列,只给出某些列的值,如下例子所示:
INSERT INTO Customers
( cust_id,
cust_name,
cust_address,
cust_city,
cust_state,
cust_zip,
cust_country)
VALUES ( '1000000006',
'Toy Land',
'123 Any Street',
'New York',
'NY',
'11111',
'USA');
我们省略了该行值的 cust_contact 和 cust_email 字段,这些省略的字段将会以 NULL 值填充。
注意:
列能被省略的前提是表的定义允许,能被省略的列必须满足以下条件之一:
- 该列定义为允许 NULL 值。
- 在表定义中给出默认值。这表示如果不给出值,将使用默认值。
3. 插入某些查询的结果
INSERT 除了一行行地插入数据外,还可以利用 SELECT 语句的结果插入表中。例子如下所示:
我们创建一个新表 CustNew,如下所示:
CREATE TABLE CustNew(
cust_id char(10) NOT NULL ,
cust_name char(50) NOT NULL ,
cust_address char(50) NULL ,
cust_city char(50) NULL ,
cust_state char(5) NULL
);
此时我们将 Customers 表中相同字段的数据插入到 CustNew 中,如下所示:
INSERT INTO CustNew (
cust_id,
cust_name,
cust_address,
cust_city,
cust_state)
SELECT
cust_id,
cust_name,
cust_address,
cust_city,
cust_state
FROM Customers;
当然我们也可以通过 SELECT 过滤出我们需要的数据添加,这些就看我们的具体需求了。
二、UPDATE
UPDATE 用于更新数据,它的使用方式有两种:
- 更新表中的特定行;
- 更新表中的所有行。
UPDATE 的通用形式如下所示:
UPDATE table_name SET update_list WHERE predicate;
其中 update_list 是一个或多个”字段赋值“的列表,格式为 column_name = value。
注意:
在使用 UPDATE 的时候一定不要忘了 WHERE 子句,否则很容易稍不注意就更新了表中的所有行。
例子如下所示:
UPDATE Customers
SET cust_email = '[email protected]'
WHERE cust_id = '1000000005';
这条语句表示的是更新 cust_id 为 100000005
的行的 cust_email 为 [email protected]
。
如果希望更新多个列的话,只需要在 SET 后面继续添加要更新的列即可,如下所示:
UPDATE Customers
SET cust_contact = 'Sam Roberts'
cust_email = '[email protected]'
WHERE cust_id = '1000000006';
三、DELETE
DELETE 用于删除数据,它的使用方式有两种:
- 删除表中的特定行;
- 删除表中的所有行。
DELETE 的使用方式和 UPDATE 有些类似,它的通用形式如下:
DELETE FROM table_name WHERE predicate;
例子:
DELETE FROM Customers WHERE cust_id = '1000000006';
执行该语句,就会将我们前面插入的数据删除。
注意:
在使用 DELETE 的时候一定不要忘了 WHERE 子句,否则很容易稍不注意就删除了表中的所有行(删库跑路)。
三、约束
约束是表定义的一部分,它们可以和字段定义或者表定义实体关联起来。约束类型如下所示:
- not null
- unique
- primary key
- foreign key
- check
- collate
1. not null
如果不希望某个字段上面出现 NULL 值,那么可以使用 not null 约束,它可以确保该字段的值不为 NULL。INSERT 语句不能向该字段插入 NULL,UPDATE 语句也不能将该字段已存在的值设置为 NULL。
如果该字段使用了 not null 约束又存在未知值的情况,那么推荐为该字段再设置一个默认值,例如下面的 phone 字段,当号码未知时,它将会被设置为默认值 UNKNOWN。
CREATE TABLE Contacts
(
id integer PRIMARY KEY,
name text not null,
phone text not null DEFAULT 'UNKNOWN',
unique(name, phone)
);
INSERT INTO Contacts (name) VALUES('Marck');
当像如上 INSERT 语句所示插入数据之后,phone 字段的值将会会 UNKNOWN,结果如下:
sqlite> SELECT * FROM Contacts;
id name phone
---------- ---------- ----------
1 Marck UNKNOWN
2. unique
unique 称为唯一性约束,它要求一个或一组字段所在的值互不相同。如果试图插入一个重复值,或将一个值更新成一个存在的值将会引发一个约束非法,并终止操作。如下所示:
sqlite> INSERT INTO Contacts (name, phone) VALUES ('Marck', 'UNKNOWN');
Error: UNIQUE constraint failed: Contacts.name, Contacts.phone
唯一性约束可在字段级或表级定义。在表级定义时,唯一性可以应用到多个字段中,例如 Contacts 的唯一性约束就是表级的:
CREATE TABLE Contacts
(
id integer PRIMARY KEY,
name text not null,
phone text not null DEFAULT 'UNKNOWN',
unique(name, phone)
);
这个唯一性约束表示 name 和 phone 字段的组合具有唯一性约束。
注意:
定义为 unique 约束的字段理论上可以放入任意多个 NULL 值。因为 NULL 值不等于任何值,包括 NULL 值。这也是 SQLite 处理定义为 unique 的字段中 NULL 的基础。
3. primary key
在 SQLite 中,定义一个表时总要确定一个主键,不管我们自己是否有定义。这个字段是一个64-bit整型字段,称为 rowid 或者 rowid 或者 oid。它的默认取值按照增序自动生成,SQLite 为主键字段提供自动增长的特性。
如果主键字段定义为 integer primary key,SQLite 将为该字段创建默认值,该默认值确保整数值是唯一的。实际上该字段就是 rowid 的别名,它们会引用相同的值。rowid 的最大值为 9223372036854775807。
如果在 integer primary key 后面加上 autoincrement,SQLite 会阻止 rowid 的回收。创建表时,如果字段包含 autoincrement 约束,SQLite 会在一个名为 sqlite_sequence 的系统表中记录该字段的最大值。后面的 INSERT 语句只使用比当前值大的,如果到达了最大值,后面的 INSERT 语句会报错。例子如下:
CREATE TABLE Maxed_out
(
id integer PRIMARY KEY AUTOINCREMENT,
x text
);
INSERT INTO Maxed_out VALUES(9223372036854775807, 'Marck');
我们插入的数据 id 字段为其允许的最大值,此时我们查看一下系统表 sqlite_sequence:
sqlite> SELECT * FROM sqlite_sequence;
name seq
---------- -------------------
Maxed_out 9223372036854775807
接着再次插入一条数据:
sqlite> INSERT INTO Maxed_out (x) VALUES('Beryl');
Error: database or disk is full
此时 SQLite 就会报错。而 autoincrement 阻止 rowid 的回收则体现在下面的例子:
DROP TABLE Maxed_out;
CREATE TABLE Maxed_out
(
id integer PRIMARY KEY AUTOINCREMENT,
x text
);
INSERT INTO Maxed_out VALUES(100, 'Marck');
先将原来的表删除然后重建,接着插入一条新数据,主键字段值为 100。此时的 sqlite_sequence 如下所示:
name seq
---------- ----------
Maxed_out 100
接着删除该行数据,然后重新插入一条新数据:
DELETE FROM Maxed_out WHERE id = 100;
INSERT INTO Maxed_out (x) VALUES('Beryl');
查看数据:
id x
---------- ----------
101 Beryl
可以看到新插入的数据是从 101 而不是从 1 开始的。主键约束还可以和 unique 一样应用于表一级上,例子如下所示:
CREATE TABLE pkey
(
x text,
y text,
primary key(x, y)
);
它的作用和 unique 类似,这里不再赘述。
4. foreign key
foreign key 也称为外键约束,它是保证引用完整性的极其重要的部分。它确保了一个表中的关键之必须从另一个表中引用。且该数据必须在另一个表中实际存在。
注意:
在 SQLite 使用外键约束时必须先打开,外键约束默认是关闭的:
PRAGMA foreign_keys = on;
foreign key 的通用形式如下所示:
CREATE TABLE table_name
(
column_definition REFERENCES foreign_table(column_name)
ON {DELETE | UPDATE} integrity_action
[not] deferrable [initially {deferred | immediate},
);
接下来介绍这些关键字各自的作用:
REFERENCES
表示引用,后面的 foreign_table(column_name) 表示引用的表和字段。ON {DELETE | UPDATE} integrity_action
表示删除或更新时的策略,integrity_action 的取值如下:- set null:如果父值被删除或不存在了,剩余的子值将改为 null。
- set default:如果父值被删除或不存在了,剩余的子值改为默认值。
- cascade:更新父值时,更新所有预知匹配的子值。删除父值时,删除所有的子值。
- restrict:更新或删除父值可能会出现孤立的子值,从而阻止事务。
- no action:不干涉操作执行,只观察变化。在整个语句结尾报出错误。
deferrable
子句控制定义的约束是立即强制实施还是延迟到整个事务结束时。
外键有助防止意外删除
定义外键之后,DBMS不允许删除在另一个表中具有关联行的行。例如,不能删除关联订单的顾客。删除顾客的唯一方法是首先删除相关的订单。由于需要一系列的删除,因而利用外键可以防止意外删除数据。
下面是一个外键约束的简单例子:
CREATE TABLE Orders2
(
order_num integer NOT NULL PRIMARY KEY,
order_date DATETIME NOT NULL,
cust_id CHAR(10) NOT NULL REFERENCES Customers(cust_id)
);
然后查询一下 Orders2 里面的数据:
order_num order_date cust_id
---------- ---------- ----------
20005 2012-05-01 1000000001
20006 2012-01-12 1000000003
20007 2012-01-30 1000000004
20008 2012-02-03 1000000005
20009 2012-02-08 1000000001
可以看到里面共有5条数据,cust_id 的取值均源自 Customers 的 cust_id 字段值。接下来尝试删除 Customers 中 cust_id 为 100000001 的值,如下所示:
sqlite> DELETE FROM Customers WHERE cust_id = '1000000001';
Error: FOREIGN KEY constraint failed
可以看到,删除失败,验证了上面的结论。接下来看一个比较复杂的外键例子:
CREATE TABLE Orders3
(
order_num integer NOT NULL PRIMARY KEY,
order_date DATETIME NOT NULL,
cust_id CHAR(10) NOT NULL REFERENCES Customers(cust_id)
on delete restrict
deferrable initially deferred
);
根据前面的说明我们可以得知:
- 字段 cust_id 引用 Customers 的 cust_id;
- 删除的时候如果会产生孤立的子值就终止事务;
- 该子句定义的约束延迟到整个事务执行结束时。
5. check
check 约束允许定义表达式来测试要插入或者更新的字段值。如果不满足设定的表达式标准,就会报错,例子如下所示:
CREATE TABLE Contacts
(
id integer PRIMARY KEY,
name text NOT NULL,
phone text NOT NULL DEFAULT 'UNKNOWN',
unique(name, phone),
check(length(phone) >= 7)
);
sqlite> INSERT INTO contacts VALUES(1, 'Marck', '10086');
Error: CHECK constraint failed: Contatcts
可以看到由于插入数据的 phone 字段值的长度小于7,所以插入失败。所有字段的 check 约束都是在修改发生前评估的,想要修改值成功,约束的表达式必须判断为真。
6. collate
关键字 collate 定义字段的排序规则。SQLite 有三种内置的排序规则:
- binary:二进制的排序规则,它是默认的排序规则,使用C函数 memcmp() 逐字节比较文本值。
- nocase:非大小写敏感的排序算法。
- reverse:与二进制排序算法相反。
我们现在重新定义一次 Contacts,并插入一条数据,如下所示:
CREATE TABLE Contacts
(
id integer PRIMARY KEY,
name text NOT NULL collate nocase,
phone text NOT NULL DEFAULT 'UNKNOWN',
unique(name, phone)
);
INSERT INTO Contacts VALUES(1, 'Marck', '10086');
此时我们的 Contacts 表中就有了一条数据了,如下所示:
id name phone
---------- ---------- ----------
1 Marck 10086
此时我们再插入一条数据:
sqlite> INSERT INTO Contacts VALUES (2, 'MARCK', '10086');
Error: UNIQUE constraint failed: Contacts.name, Contacts.phone
可以看到发生了错误。原因是根据 name 字段的排序规则,name 是大小写不敏感的,所以 “MARCK” 和 “Marck” 是相同的,表中已经存在该值,所以插入的数据违反了唯一性约束。
参考
《SQLite权威指南》
- 第4章 sqlite中的高级sql
《SQL必知必会》
- 第15课 插入数据
- 第16课 更新和删除数据
- 第22课 高级SQL特性