SQL 如何插入、删除和更新数据

本文将会给大家介绍 DBMS 中用来更新表中数据的方法。SQL 数据的更新处理大体可以分为插入(INSERT)、删除(DELETE)和更新(UPDATE)三类。本文将会对这三类更新方法进行详细介绍。

一、数据的插入(INSERT 语句的使用方法)

1.1 什么是 INSERT

SQL 如何对表进行创建、更新和删除操作 给大家介绍了用来创建表的 CREATE TABLE 语句。通过 CREATE TABLE 语句创建出来的表,可以被认为是一个空空如也的箱子。

只有把数据装入到这个箱子后,它才能称为数据库。用来装入数据的 SQL 就是 INSERT(插入)(图 1)。

INSERT(插入)的流程

图 1 INSERT(插入)的流程

本节将会和大家一起学习 INSERT 语句。

要学习 INSERT 语句,我们得首先创建一个名为 ProductIns 的表。请大家执行代码清单 1 中的 CREATE TABLE 语句。

该表除了为 sale_price 列(销售单价)设置了 DEFAULT 0 的约束之外,其余内容与之前使用的 Product(商品)表完全相同。

DEFAULT 0 的含义将会在随后进行介绍,大家暂时可以忽略。

代码清单 1 创建 ProductIns 表的 CREATE TABLE 语句

1
2
3
4
5
6
7
8
CREATE TABLE ProductIns
(product_id      CHAR(4)      NOT NULL,
 product_name    VARCHAR(100) NOT NULL,
 product_type    VARCHAR(32)  NOT NULL,
 sale_price      INTEGER      DEFAULT 0,
 purchase_price  INTEGER      ,
 regist_date     DATE         ,
 PRIMARY KEY (product_id));

如前所述,这里仅仅是创建出了一个表,并没有插入数据。接下来,我们就向 ProductIns 表中插入数据。

1.2 INSERT 语句的基本语法

SQL 如何对表进行创建、更新和删除操作 中讲到向 CREATE TABLE 语句创建出的 Product 表中插入数据的 SQL 语句时,曾介绍过 INSERT 语句的使用示例,但当时的目的只是为学习 SELECT 语句准备所需的数据,并没有详细介绍其语法。

下面就让我们来介绍一下 INSERT 语句的语法结构。

INSERT 语句的基本语法如下所示。

语法 1 INSERT 语句

1
INSERT INTO <表名> (1, 2, 3, ……) VALUES (1, 2, 3, ……);

例如,我们要向 ProductIns 表中插入一行数据,各列的值如下所示。

product_id(商品编号)product_name(商品名称)product_type(商品种类)sale_price(销售单价)purchase_price(进货单价)regist_date(登记日期)
0001T 恤衫衣服10005002009-09-20

此时使用的 INSERT 语句可参见代码清单 2。

代码清单 2 向表中插入一行数据

1
2
INSERT INTO ProductIns (product_id, product_name, product_type, sale_price, purchase_price, regist_date)
VALUES ('0001', 'T恤衫', '衣服', 1000, 500, '2009-09-20');

由于 product_id 列(商品编号)和 product_name 列(商品名称)是字符型,所以插入的数据需要像 '0001' 这样用单引号括起来。日期型的 regist_date(登记日期)列也是如此 1

将列名和值用逗号隔开,分别括在 () 内,这种形式称为清单。代码清单 2 中的 INSERT 语句包含如下两个清单。

A:列清单(product_id, product_name, product_type, sale_price, purchase_price, regist_date)

B:值清单('0001', 'T恤衫', '衣服', 1000, 500,'2009-09-20')

当然,表名后面的列清单和 VALUES 子句中的值清单的列数必须保持一致。如下所示,列数不一致时会出错,无法插入数据 2

1
2
3
-- VALUES子句中的值清单缺少一列
INSERT INTO ProductIns (product_id, product_name, product_type, sale_price, purchase_price, regist_date)
VALUES ('0001', 'T恤衫', '衣服', 1000, 500);

此外,原则上,执行一次 INSERT 语句会插入一行数据 3。因此,插入多行时,通常需要循环执行相应次数的 INSERT 语句。

1.3 列清单的省略

对表进行全列 INSERT 时,可以省略表名后的列清单。这时 VALUES 子句的值会默认按照从左到右的顺序赋给每一列。因此,代码清单 3 中的两个 INSERT 语句会插入同样的数据。

代码清单 3 省略列清单

1
2
3
4
5
6
-- 包含列清单
INSERT INTO ProductIns (product_id, product_name, product_type, sale_price, purchase_price, regist_date)
VALUES ('0005', '高压锅', '厨房用具', 6800, 5000, '2009-01-15');

-- 省略列清单
INSERT INTO ProductIns VALUES ('0005', '高压锅', '厨房用具', 6800, 5000, '2009-01-15');

1.4 插入 NULL

INSERT 语句中想给某一列赋予 NULL 值时,可以直接在 VALUES 子句的值清单中写入 NULL

例如,要向 purchase_price 列(进货单价)中插入 NULL,就可以使用代码清单 4 中的 INSERT 语句。

代码清单 4 向 purchase_price 列中插入 NULL

1
2
INSERT INTO ProductIns (product_id, product_name, product_type, sale_price, purchase_price, regist_date)
VALUES ('0006', '叉子', '厨房用具', 500, NULL, '2009-09-20');

但是,想要插入 NULL 的列一定不能设置 NOT NULL 约束。向设置了 NOT NULL 约束的列中插入 NULL 时,INSERT 语句会出错,导致数据插入失败。

插入失败指的是希望通过 INSERT 语句插入的数据无法正常插入到表中,但之前已经插入的数据并不会被破坏 4

1.5 插入默认值

我们还可以向表中插入默认值(初始值)。可以通过在创建表的 CREATE TABLE 语句中设置 DEFAULT 约束来设定默认值。

本文开头创建的 ProductIns 表的定义部分请参见代码清单 5。其中 DEFAULT 0 就是设置 DEFAULT 约束的部分。像这样,我们可以通过“DEFAULT <默认值>”的形式来设定默认值。

代码清单 5 创建 ProductIns 表的 CREATE TABLE 语句(节选)

1
2
3
4
5
6
CREATE TABLE ProductIns
(product_id     CHAR(4)  NOT NULL,
         (略)
 sale_price      INTEGER  DEFAULT 0, -- 销售单价的默认值设定为0;
         (略)
 PRIMARY KEY (product_id));

如果在创建表的同时设定了默认值,就可以在 INSERT 语句中自动为列赋值了。默认值的使用方法通常有显式和隐式两种。

  • 通过显式方法插入默认值

    VALUES 子句中指定 DEFAULT 关键字(代码清单 6)。

    代码清单 6 通过显式方法设定默认值

    1
    2
    
    INSERT INTO ProductIns (product_id, product_name, product_type, sale_price, purchase_price, regist_date)
    VALUES ('0007', '擦菜板', '厨房用具', DEFAULT, 790, '2009-04-28');
    

    这样一来,RDBMS 就会在插入记录时自动把默认值赋给对应的列。

    我们可以使用 SELECT 语句来确认通过 INSERT 语句插入的数据行。

    1
    2
    
    -- 确认插入的数据行;
    SELECT * FROM ProductIns WHERE product_id = '0007';
    

    因为 sale_price 列(销售单价)的默认值是 0,所以 sale_price 列被赋予了值 0

    执行结果:

    1
    2
    3
    
    product_id | product_name | product_type | sale_price | purchase_price | regist_date
    -----------+--------------+--------------+------------+----------------+----------
    0007      | 擦菜板       | 厨房用具     |          0 |            790  | 2008-04-28
    
  • 通过隐式方法插入默认值

    插入默认值时也可以不使用 DEFAULT 关键字,只要在列清单和 VALUES 中省略设定了默认值的列就可以了。

    我们可以像代码清单 7 那样,从 INSERT 语句中删除 sale_price 列(销售单价)。

    代码清单 7 通过隐式方法设定默认值

    代码清单 7 通过隐式方法设定默认值

    这样也可以给 sale_price 赋上默认值 0

    那么在实际使用中哪种方法更好呢?笔者建议大家使用显式的方法。因为这样可以一目了然地知道 sale_price 列使用了默认值,SQL 语句的含义也更加容易理解。

    说到省略列名,还有一点要说明一下。如果省略了没有设定默认值的列,该列的值就会被设定为 NULL

    因此,如果省略的是设置了 NOT NULL 约束的列,INSERT 语句就会出错(代码清单 8)。请大家一定要注意。

    代码清单 8 未设定默认值的情况

    1
    2
    3
    4
    5
    6
    7
    
    -- 省略purchase_price列(无约束):会赋予“NULL”
    INSERT INTO ProductIns (product_id, product_name, product_type, sale_price, regist_date)
    VALUES ('0008', '圆珠笔', '办公用品', 100, '2009-11-11');
    
    -- 省略product_name列(设置了NOT NULL约束):错误!
    INSERT INTO ProductIns (product_id, product_type, sale_price,purchase_price, regist_date)
    VALUES ('0009', '办公用品', 1000, 500, '2009-12-12');
    

1.6 从其他表中复制数据

要插入数据,除了使用 VALUES 子句指定具体的数据之外,还可以从其他表中复制数据。下面我们就来学习如何从一张表中选取数据,复制到另外一张表中。

要学习该方法,我们首先得创建一张表(代码清单 9)。

代码清单 9 创建 ProductCopy 表的 CREATE TABLE 语句

1
2
3
4
5
6
7
8
9
-- 用来插入数据的商品复制表
CREATE TABLE ProductCopy
(product_id      CHAR(4)      NOT NULL,
 product_name    VARCHAR(100) NOT NULL,
 product_type    VARCHAR(32)  NOT NULL,
 sale_price      INTEGER      ,
 purchase_price  INTEGER      ,
 regist_date     DATE         ,
 PRIMARY KEY (product_id));

ProductCopy(商品复制)表的结构与之前使用的 Product(商品)表完全一样,只是更改了一下表名而已。

接下来,就让我们赶快尝试一下将 Product 表中的数据插入到 ProductCopy 表中吧。代码清单 10 中的语句可以将查询的结果直接插入到表中。

代码清单 10 INSERT … SELECT 语句

1
2
3
4
-- 将商品表中的数据复制到商品复制表中
INSERT INTO ProductCopy (product_id, product_name, product_type, sale_price, purchase_price, regist_date)
SELECT product_id, product_name, product_type, sale_price, purchase_price, regist_date
  FROM Product;

执行该 INSERT … SELECT 语句时,如果原来 Product 表中有 8 行数据,那么 ProductCopy 表中也会插入完全相同的 8 行数据。

当然,Product 表中的原有数据不会发生改变。因此,INSERT … SELECT 语句可以在需要进行数据备份时使用(图 2)。

INSERT ... SELECT 语句

图 2 INSERT … SELECT 语句

  • 多种多样的 SELECT 语句

    INSERT 语句中的 SELECT 语句,也可以使用 WHERE 子句或者 GROUP BY 子句等。

    目前为止学到的各种 SELECT 语句也都可以使用 5。对在关联表之间存取数据来说,这是非常方便的功能。

    接下来我们尝试一下使用包含 GROUP BY 子句的 SELECT 语句进行插入。代码清单 11 中的语句创建了一个用来插入数据的表。

    代码清单 11 创建 ProductType 表的 CREATE TABLE 语句

    1
    2
    3
    4
    5
    6
    
    -- 根据商品种类进行汇总的表;
    CREATE TABLE ProductType
    (product_type       VARCHAR(32)     NOT NULL,
    sum_sale_price     INTEGER         ,
    sum_purchase_price INTEGER         ,
    PRIMARY KEY (product_type));
    

    该表是用来存储根据商品种类(product_type)计算出的销售单价合计值以及进货单价合计值的表。

    下面就让我们使用代码清单 12 中的 INSERT ... SELECT 语句,从 Product 表中选取出数据插入到这张表中吧。

    代码清单 12 插入其他表中数据合计值的 INSERT … SELECT 语句

    1
    2
    3
    4
    
    INSERT INTO ProductType (product_type, sum_sale_price, sum_purchase_price)
    SELECT product_type, SUM(sale_price), SUM(purchase_price)
    FROM Product
    GROUP BY product_type;
    

    通过 SELECT 语句对插入结果进行确认,我们发现 ProductType 表中插入了以下 3 行数据。

    1
    2
    
    -- 确认插入的数据行
    SELECT * FROM ProductType;
    

    执行结果:

    1
    2
    3
    4
    5
    
    product_type | sum_sale_price  | sum_purchase_price
    --------------+-----------------+--------------------
    衣服         |            5000 |               3300
    办公用品     |             600 |                320
    厨房用具     |           11180 |               8590
    

二、数据的删除(DELETE 语句的使用方法)

2.1 DROP TABLE 语句和 DELETE 语句

上一节我们学习了插入数据的方法,本节我们来学习如何删除数据。删除数据的方法大体可以分为以下两种。

DROP TABLE 语句可以将表完全删除

DELETE 语句会留下表(容器),而删除表中的全部数据

① 中的 DROP TABLE 语句我们已经在 SQL 如何对表进行创建、更新和删除操作 中学过了,此处再简单回顾一下。

DROP TABLE 语句会完全删除整张表,因此删除之后再想插入数据,就必须使用 CREATE TABLE 语句重新创建一张表。

反之,② 中的 DELETE 语句在删除数据(行)的同时会保留数据表,因此可以通过 INSERT 语句再次向表中插入数据。

本节所要介绍的删除数据,指的就是只删除数据的 DELETE 语句。

此外,我们在 SQL 如何对表进行创建、更新和删除操作 中也提到过,不管使用哪种方法,删除数据时都要慎重,一旦误删,想要恢复数据就会变得十分困难。

2.2 DELETE 语句的基本语法

DELETE 语句的基本语法如下所示,十分简单。

语法 2 保留数据表,仅删除全部数据行的 DELETE 语句

1
DELETE FROM <表名>;

执行使用该基本语法的 DELETE 语句,就可以删除指定的表中的全部数据行了。因此,想要删除 Product 表中全部数据行,就可以参照代码清单 13 来书写 DELETE 语句。

代码清单 13 清空 Product 表

1
DELETE FROM Product;

如果语句中忘了写 FROM,而是写成了“DELETE <表名>”,或者写了多余的列名,都会出错,无法正常执行,请大家特别注意。

前者无法正常执行的原因是删除对象不是表,而是表中的数据行(记录)。这样想的话就很容易理解了吧 6

后者错误的原因也是如此。因为 DELETE 语句的对象是行而不是列,所以 DELETE 语句无法只删除部分列的数据。

因此,在 DELETE 语句中指定列名是错误的。当然,使用星号的写法(DELETE * FROM Product;)也是不对的,同样会出错。

2.3 指定删除对象的 DELETE 语句(搜索型 DELETE)

想要删除部分数据行时,可以像 SELECT 语句那样使用 WHERE 子句指定删除条件。这种指定了删除对象的 DELETE 语句称为搜索型 DELETE 7

搜索型 DELETE 的语法如下所示。

语法 3 删除部分数据行的搜索型 DELETE

1
2
DELETE FROM <表名>
 WHERE <条件>;

下面让我们以 Product(商品)表为例,来具体研究一下如何进行数据删除(表 1)。

表 1 Product 表

product_id(商品编号)product_name(商品名称)product_type(商品种类)sale_price(销售单价)purchase_price(进货单价)regist_date(登记日期)
0001T 恤衫衣服10005002009-09-20
0002打孔器办公用品5003202009-09-11
0003运动 T 恤衣服40002800
0004菜刀厨房用具300028002009-09-20
0005高压锅厨房用具680050002009-01-15
0006叉子厨房用具5002009-09-20
0007擦菜板厨房用具8807902008-04-28
0008圆珠笔办公用品1002009-11-11

假设我们要删除销售单价(sale_price)大于等于 4000 元的数据(代码清单 14)。上述表中满足该条件的是“运动 T 恤”和“高压锅”。

代码清单 14 删除销售单价(sale_price)大于等于 4000 元的数据

1
2
DELETE FROM Product
 WHERE sale_price >= 4000;

WHERE 子句的书写方式与此前介绍的 SELECT 语句完全一样。

通过使用 SELECT 语句确认,表中的数据被删除了 2 行,只剩下 6 行。

1
2
-- 确认删除后的结果
SELECT * FROM Product;

执行结果:

1
2
3
4
5
6
7
8
product_id | product_name | product_type | sale_price | purchase_price | regist_date
-----------+--------------+--------------+------------+----------------+-----------
 0001      | T恤衫        | 衣服         |        1000 |             500 | 2009-09-20
 0002      | 打孔器       | 办公用品     |         500 |             320 | 2009-09-11
 0004      | 菜刀         | 厨房用具     |        3000 |            2800 | 2009-09-20
 0006      | 叉子         | 厨房用具     |         500 |                 | 2009-09-20
 0007      | 擦菜板       | 厨房用具     |         880 |             790 | 2008-04-28
 0008      | 圆珠笔       | 办公用品     |         100 |                 | 2009-11-11

SELECT 语句不同的是,DELETE 语句中不能使用 GROUP BYHAVINGORDER BY 三类子句,而只能使用 WHERE 子句。

原因很简单,GROUP BYHAVING 是从表中选取数据时用来改变抽取数据形式的,而 ORDER BY 是用来指定取得结果显示顺序的。

因此,在删除表中数据时它们都起不到什么作用。

三、数据的更新(UPDATE 语句的使用方法)

3.1 UPDATE 语句的基本语法

使用 INSERT 语句向表中插入数据之后,有时却想要再更改数据,例如“将商品销售单价登记错了”等的时候。

这时并不需要把数据删除之后再重新插入,使用 UPDATE 语句就可以改变表中的数据了。

INSERT 语句、DELETE 语句一样,UPDATE 语句也属于 DML 语句。通过执行该语句,可以改变表中的数据。其基本语法如下所示。

语法 4 改变表中数据的 UPDATE 语句

1
2
UPDATE <表名>
   SET <列名> = <表达式>;

将更新对象的列和更新后的值都记述在 SET 子句中。

我们还是以 Product(商品)表为例,由于之前我们删除了“销售单价大于等于 4000 元”的 2 行数据,现在该表中只剩下了 6 行数据了(表 2)。

表 2 Product 表

product_id(商品编号)product_name(商品名称)product_type(商品种类)sale_price(销售单价)purchase_price(进货单价)regist_date(登记日期)
0001T 恤衫衣服10005002009-09-20
0002打孔器办公用品5003202009-09-11
0004菜刀厨房用具300028002009-09-20
0006叉子厨房用具5002009-09-20
0007擦菜板厨房用具8807902008-04-28
0008圆珠笔办公用品1002009-11-11

接下来,让我们尝试把 regist_date 列(登记日期)的所有数据统一更新为“2009-10-10”。具体的 SQL 语句请参见代码清单 15。

代码清单 15 将登记日期全部更新为“2009-10-10”

1
2
UPDATE Product
   SET regist_date = '2009-10-10';

表中的数据有何变化呢?我们通过 SELECT 语句来确认一下吧。

1
2
-- 确认更新内容
SELECT * FROM Product ORDER BY product_id;

执行结果:

执行结果

此时,连登记日期原本为 NULL 的数据行(运动 T 恤)的值也更新为 2009-10-10 了。

执行结果

3.2 指定条件的 UPDATE 语句(搜索型 UPDATE)

接下来,让我们看一看指定更新对象的情况。

更新数据时也可以像 DELETE 语句那样使用 WHERE 子句,这种指定更新对象的 UPDATE 语句称为搜索型 UPDATE 语句

该语句的语法如下所示(与 DELETE 语句十分相似)。

语法 5 更新部分数据行的搜索型 UPDATE

1
2
3
UPDATE <表名>
   SET <列名> = <表达式>
 WHERE <条件>;

例如,将商品种类(product_type)为厨房用具的记录的销售单价(sale_price)更新为原来的 10 倍,请参见代码清单 16。

代码清单 16 将商品种类为厨房用具的记录的销售单价更新为原来的 10 倍

1
2
3
UPDATE Product
   SET sale_price = sale_price * 10
 WHERE product_type = '厨房用具';

我们可以使用如下 SELECT 语句来确认更新后的内容。

1
2
-- 确认更新内容
SELECT * FROM Product ORDER BY product_id;

执行结果:

执行结果

该语句通过 WHERE 子句中的“product_type = '厨房用具'”条件,将更新对象限定为 3 行。

然后通过 SET 子句中的表达式 sale_price * 10,将原来的单价扩大了 10 倍。

SET 子句中赋值表达式的右边不仅可以是单纯的值,还可以是包含列的表达式。

3.3 使用 NULL 进行更新

使用 UPDATE 也可以将列更新为 NULL(该更新俗称为 NULL 清空)。

此时只需要将赋值表达式右边的值直接写为 NULL 即可。

例如,我们可以将商品编号(product_id)为 0008 的数据(圆珠笔)的登记日期(regist_date)更新为 NULL(代码清单 17)。

代码清单 17 将商品编号为 0008 的数据(圆珠笔)的登记日期更新为 NULL

1
2
3
UPDATE Product
   SET regist_date = NULL
 WHERE product_id = '0008';
1
2
-- 确认更新内容
SELECT * FROM Product ORDER BY product_id;

执行结果:

执行结果

INSERT 语句一样,UPDATE 语句也可以将 NULL 作为一个值来使用。

但是,只有未设置 NOT NULL 约束和主键约束的列才可以清空为 NULL

如果将设置了上述约束的列更新为 NULL,就会出错,这点与 INSERT 语句相同。

3.4 多列更新

UPDATE 语句的 SET 子句支持同时将多个列作为更新对象。

例如我们刚刚将销售单价(sale_price)更新为原来的 10 倍,如果想同时将进货单价(purchase_price)更新为原来的一半,该怎么做呢?

最容易想到的解决办法可能就是像代码清单 18 那样,执行两条 UPDATE 语句。

代码清单 18 能够正确执行的繁琐的 UPDATE 语句

1
2
3
4
5
6
7
8
-- 一条UPDATE语句只更新一列
UPDATE Product
   SET sale_price = sale_price * 10
 WHERE product_type = '厨房用具';

UPDATE Product
   SET purchase_price = purchase_price / 2
 WHERE product_type = '厨房用具';

虽然这样也能够正确地更新数据,但执行两次 UPDATE 语句不但有些浪费,而且增加了 SQL 语句的书写量。

其实,我们可以将其合并为一条 UPDATE 语句来处理。合并的方法有两种,请参见代码清单 19 和代码清单 20。

方法 ①:代码清单 19 将代码清单 18 的处理合并为一条 UPDATE 语句

1
2
3
4
5
-- 使用逗号对列进行分隔排列
UPDATE Product
   SET sale_price = sale_price * 10,
       purchase_price = purchase_price / 2
 WHERE product_type = '厨房用具';

方法 ②:代码清单 20 将代码清单 18 的处理合并为一条 UPDATE 语句

1
2
3
4
-- 将列用()括起来的清单形式
UPDATE Product
   SET (sale_price, purchase_price) = (sale_price * 10, purchase_price / 2)
 WHERE product_type = '厨房用具';

执行上述两种 UPDATE 语句,都可以得到相同的结果:只有厨房用具的销售单价(sale_price)和进货单价(purchase_price)被更新了。

1
2
-- 确认更新内容
SELECT * FROM Product ORDER BY product_id;

执行结果:

执行结果

当然,SET 子句中的列不仅可以是两列,还可以是三列或者更多。

需要注意的是第一种方法——使用逗号将列进行分隔排列(代码清单 19),这一方法在所有的 DBMS 中都可以使用。

但是第二种方法——将列清单化(代码清单 20),这一方法在某些 DBMS 中是无法使用的 8。因此,实际应用中通常都会使用第一种方法。

(完)


  1. 有关日期型的介绍,请参考 SQL 如何对表进行创建、更新和删除操作。 ↩︎

  2. 但是使用默认值时列数无需完全一致。相关内容将会在随后的“插入默认值”中进行介绍。 ↩︎

  3. 插入多行的情况,请参考专栏“多行 INSERT”。 ↩︎

  4. 不仅是 INSERTDELETEUPDATE 等更新语句也一样,SQL 语句执行失败时都不会对表中数据造成影响。 ↩︎

  5. 但即使指定了 ORDER BY 子句也没有任何意义,因为无法保证表内部记录的排列顺序。 ↩︎

  6. INSERT 语句相同,数据的更新也是以记录为基本单位进行的。下一节将要学习的 UPDATE 语句也是如此。 ↩︎

  7. 虽然“搜索型 DELETE”是正式用语,但实际上这种说法并不常用,而是简单地称为 DELETE 语句。 ↩︎

  8. 可以在 PostgreSQL 和 DB2 中使用。 ↩︎