SQLite学习笔记(五)

版权声明:本文为博主原创文章,转载请注明出处: https://blog.csdn.net/qq_38182125/article/details/89439389

概述

本篇文章结构如下:

  • 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特性

猜你喜欢

转载自blog.csdn.net/qq_38182125/article/details/89439389