[PSQL] SQL基础教程读书笔记(Chapter1-4)

SQL基础教程读书笔记 MICK

示例程序下载 http://www.ituring.com.cn/book/1880

说明:如下笔记中的测试基于postgresql14

命令行连接本地PSQL:  psql -U <username> -d <dbname> -h 127.0.0.1 -W

# psql -U postgres -d shop -h 127.0.0.1 -W
Password:
psql (14.1)
Type "help" for help.

shop=#

目录

1 数据库和SQL

1-3 SQL概要

SQL语句及其种类

1-4 表的创建

数据库的创建(CREATE DATABASE语句)

表的创建(CREATE TABLE语句)

数据类型的指定

约束的设置

1-5 表的删除和更新

表的删除(DROP TABLE语句)

表定义的更新(ALTER TABLE语句)

向Product表中插入数据

2 查询基础

2-1 SELECT语句基础

为列设定别名

常数的查询

从结果中删除重复行

注释的书写方法

2-2 算数运算符与比较运算符

需要注意NULL

2-3 逻辑运算符

含有NULL时的真值

3 聚合与排序

3-1 对表进行聚合查询

聚合函数

计算NULL之外的数据的行数

计算合计值

计算平均值

使用聚合函数删除重复值(关键字DISTINCT)

3-2 对表进行分组

GROUP BY子句

聚合键中包含NULL的情况

使用WHERE子句时GROUP BY的执行结果

与聚合函数和GROUP BY子句有关的常见错误

3-3 为聚合结果指定条件

HAVING子句

HAVING子句的构成要素

相对于HAVING子句, 更适合写在WHERE子句中的条件

3-4 对查询结果进行排序

ORDER BY子句

指定升序或降序

指定多个排序键

NULL的顺序

在排序键中使用显示用的别名

ORDER BY子句中可以使用的列

4 数据更新

4-1 数据的插入(INSERT语句的使用方法)

INSERT语句的基本语法

列清单的省略

插入NULL

插入默认值

从其它表中复制数据

4-2 数据的删除(DELETE语句的使用方法)

DELETE语句的基本语法

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

删除和舍弃

4-3 数据的更新(UPDATE语句的使用方法)

UPDATE语句的基本语法

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

使用NULL进行更新

多列更新

4-4 事务

创建事务

ACID特性


1 数据库和SQL

1-3 SQL概要

SQL语句及其种类

SQL 语句可以分为以下三类,实际使用的SQL语句当中有90%属于DML

DDL(Data Definition Language,数据定义语言)用来创建或者删除存储数据用的数据库以及数据库中的表等对象。DDL 包含以下几种指令,
CREATE:创建数据库和表等对象
DROP: 删除数据库和表等对象
ALTER: 修改数据库和表等对象的结构

DML(Data Manipulation Language,数据操纵语言)用来查询或者变更表中的记录。DML 包含以下几种指令,
SELECT:查询表中的数据
INSERT:向表中插入新数据
UPDATE:更新表中的数据
DELETE:删除表中的数据

DCL(Data Control Language,数据控制语言)用来确认或者取消对数据库中的数据进行的变更。除此之外,还可以对 RDBMS 的用户是否有权限操作数据库中的对象(数据库表等)进行设定。DCL 包含以下几种指令。
COMMIT: 确认对数据库中的数据进行的变更
ROLLBACK:取消对数据库中的数据进行的变更
GRANT: 赋予用户操作权限
REVOKE: 取消用户的操作权限

1-4 表的创建

数据库的创建(CREATE DATABASE语句)

语法1-1 创建数据库的CREATE DATABASE语句
CREATE DATABASE <数据库名称>;

代码清单1-1  创建数据库shop的CREATE DATABASE语句

CREATE DATABASE shop;

表的创建(CREATE TABLE语句)

语法1-2 创建表的CREATE TABLE语句
CREATE TABLE <表名>
(<列名1> <数据类型> <该列所需约束>,
 <列名2> <数据类型> <该列所需约束>,
...
 <该表的约束1>, <该表的约束2>,……)

代码清单1-2 创建Product表的CREATE TABLE语句

CREATE TABLE Product
(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));

数据类型的指定

CHAR型 (定长字符串)
CHAR(10) 或者 CHAR(200) ,在括号中指定该列可以存储的字符串的长度(最大长度)
当列中存储的字符串长度达不到最大长度的时候,使用半角空格进行补足

VARCHAR型(可变长字符串)
可以通过括号内的数字来指定字符串的长度(最大长度)
即使字符数未达到最大长度,也不会用半角空格补足

约束的设置

Product 表中设置了两种约束
Product 表的 product_id 列、product_name 列和product_type 列设置了 NOT NULL 约束
PRIMARY KEY (product_id) 是用来给 product_id 列设置主键约束

1-5 表的删除和更新

表的删除(DROP TABLE语句)

语法1-3 删除表时使用的DROP TABLE语句
DROP TABLE <表名>;

表定义的更新(ALTER TABLE语句)

语法1-4 添加列的ALTER TABLE语句
ALTER TABLE <表名> ADD COLUMN <列的定义>;

代码清单1-4 添加一列可以存储100位的可变长字符串的product_name_pinyin列

ALTER TABLE Product ADD COLUMN product_name_pinyin VARCHAR(100);

语法1-5 删除列的ALTER TABLE语句
ALTER TABLE <表名> DROP COLUMN <列名>;

代码清单1-5 删除product_name_pinyin列

ALTER TABLE Product DROP COLUMN product_name_pinyin;

补充:

添加NOT NULL约束
ALTER TABLE <表名> ALTER COLUMN <列名> SET NOT NULL;

去除NOT NULL约束
ALTER TABLE <表名> ALTER COLUMN <列名> DROP NOT NULL;

shop=# ALTER TABLE Product ALTER COLUMN product_type DROP NOT NULL;
ALTER TABLE
shop=# \d Product
                          Table "public.product"
     Column     |          Type          | Collation | Nullable | Default
----------------+------------------------+-----------+----------+---------
 product_id     | character(4)           |           | not null |
 product_name   | character varying(100) |           | not null |
 product_type   | character varying(32)  |           |          |
 sale_price     | integer                |           |          |
 purchase_price | integer                |           |          |
 regist_date    | date                   |           |          |
Indexes:
    "product_pkey" PRIMARY KEY, btree (product_id)

shop=#
shop=# ALTER TABLE Product ALTER COLUMN product_type SET NOT NULL;
ALTER TABLE
shop=# \d Product
                          Table "public.product"
     Column     |          Type          | Collation | Nullable | Default
----------------+------------------------+-----------+----------+---------
 product_id     | character(4)           |           | not null |
 product_name   | character varying(100) |           | not null |
 product_type   | character varying(32)  |           | not null |
 sale_price     | integer                |           |          |
 purchase_price | integer                |           |          |
 regist_date    | date                   |           |          |
Indexes:
    "product_pkey" PRIMARY KEY, btree (product_id)

shop=#

添加主键
ALTER TABLE <表名> ADD PRIMARY KEY (<列名>);  

去除主键
ALTER TABLE <表名> DROP CONSTRAINT <主键名>;

shop=# ALTER TABLE Product ADD PRIMARY KEY  (product_name);
ERROR:  multiple primary keys for table "product" are not allowed
shop=# ALTER TABLE Product DROP CONSTRAINT product_pkey;
ALTER TABLE
shop=# ALTER TABLE Product ADD PRIMARY KEY  (product_name);
ALTER TABLE
shop=# \d Product
……
Indexes:
    "product_pkey" PRIMARY KEY, btree (product_name)

shop=# ALTER TABLE Product DROP CONSTRAINT product_pkey;
ALTER TABLE
shop=# ALTER TABLE Product ADD CONSTRAINT product_pkey PRIMARY KEY(product_name);
ALTER TABLE
shop=# \d Product
……
Indexes:
    "product_pkey" PRIMARY KEY, btree (product_name)

shop=#

更改列名
ALTER TABLE <表名> RENAME COLUMN <列名> TO <新列名>;

shop=# ALTER TABLE Product RENAME COLUMN product_name TO product_label;
ALTER TABLE
shop=# \d Product
                          Table "public.product"
     Column     |          Type          | Collation | Nullable | Default
----------------+------------------------+-----------+----------+---------
 product_id     | character(4)           |           | not null |
 product_label  | character varying(100) |           | not null |
 product_type   | character varying(32)  |           | not null |
...

shop=#

更改列类型
ALTER TABLE <表名> ALTER COLUMN <列名> TYPE <数据类型>;

shop=# ALTER TABLE Product
shop-# ALTER COLUMN product_label TYPE Varchar(30),
shop-# ALTER COLUMN product_type TYPE Varchar(30);
ALTER TABLE
shop=# \d Product
                         Table "public.product"
     Column     |         Type          | Collation | Nullable | Default
----------------+-----------------------+-----------+----------+---------
 product_id     | character(4)          |           | not null |
 product_label  | character varying(30) |           | not null |
 product_type   | character varying(30) |           | not null |
...

shop=#

添加默认值
ALTER TABLE <表名> ALTER COLUMN <列名> SET DEFAULT <默认值>;

shop=# ALTER TABLE Product ALTER COLUMN product_type SET DEFAULT 'other type';
ALTER TABLE
shop=# \d Product;
                                     Table "public.product"
     Column     |         Type          | Collation | Nullable |             Default
----------------+-----------------------+-----------+----------+---------------------------------
 product_id     | character(4)          |           | not null |
 product_label  | character varying(30) |           | not null |
 product_type   | character varying(30) |           | not null | 'other type'::character varying
...

shop=#

去除默认值
ALTER TABLE <表名> ALTER COLUMN <列名> DROP DEFAULT;

shop=# ALTER TABLE Product ALTER COLUMN product_type DROP DEFAULT;
ALTER TABLE
shop=# \d Product;
                         Table "public.product"
     Column     |         Type          | Collation | Nullable | Default
----------------+-----------------------+-----------+----------+---------
 product_id     | character(4)          |           | not null |
 product_label  | character varying(30) |           | not null |
 product_type   | character varying(30) |           | not null |
...

shop=#

向Product表中插入数据

代码清单1-6 向Product表中插入数据的SQL语句

-- DML :插入数据
BEGIN TRANSACTION;

INSERT INTO Product VALUES ('0001', 'T恤' ,'衣服', 1000, 500, '2009-09-20');
INSERT INTO Product VALUES ('0002', '打孔器', '办公用品', 500, 320, '2009-09-11');
INSERT INTO Product VALUES ('0003', '运动T恤', '衣服', 4000, 2800, NULL);
INSERT INTO Product VALUES ('0004', '菜刀', '厨房用具', 3000, 2800, '2009-09-20');
INSERT INTO Product VALUES ('0005', '高压锅', '厨房用具', 6800, 5000, '2009-01-15');
INSERT INTO Product VALUES ('0006', '叉子', '厨房用具', 500, NULL, '2009-09-20');
INSERT INTO Product VALUES ('0007', '擦菜板', '厨房用具', 880, 790, '2008-04-28');
INSERT INTO Product VALUES ('0008', '圆珠笔', '办公用品', 100, NULL, '2009-11-11');

COMMIT;

说明:在MySQL中运行时,需要把 BEGIN TRANSACTION; 改写成 START TRANSACTION;

2 查询基础

2-1 SELECT语句基础

为列设定别名

代码清单2-4 为列设定别名

shop=# SELECT product_id AS id,
shop-#  product_name AS name,
shop-#  purchase_price AS price
shop-#  FROM Product;
  id  |  name   | price
------+---------+-------
 0001 | T恤     |   500
 0002 | 打孔器  |   320
 0003 | 运动T恤 |  2800
 0004 | 菜刀    |  2800
 0005 | 高压锅  |  5000
 0006 | 叉子    |
 0007 | 擦菜板  |   790
 0008 | 圆珠笔  |
(8 rows)

shop=#

别名可以使用中文,使用中文时需要用双引号(")括起来。

shop=# SELECT product_id AS "商品编号",
shop-#  product_name AS "商品名称",
shop-#  purchase_price AS "进货单价"
shop-#  FROM Product;
 商品编号 | 商品名称 | 进货单价
----------+----------+----------
 0001     | T恤      |      500
 0002     | 打孔器   |      320
 0003     | 运动T恤  |     2800
 0004     | 菜刀     |     2800
 0005     | 高压锅   |     5000
 0006     | 叉子     |
 0007     | 擦菜板   |      790
 0008     | 圆珠笔   |
(8 rows)

shop=#

常数的查询

代码清单2-6 查询常数

shop=# SELECT '商品' AS string, 38 AS number, '2009-02-24' AS date,
shop-#  product_id  FROM Product;
 string | number |    date    | product_id
--------+--------+------------+------------
 商品   |     38 | 2009-02-24 | 0001
 商品   |     38 | 2009-02-24 | 0002
...
 商品   |     38 | 2009-02-24 | 0008
(8 rows)

shop=#

从结果中删除重复行

代码清单2-7 使用DISTINCT删除product_type列中重复的数据

shop=# SELECT DISTINCT product_type  FROM Product;
 product_type
--------------
 衣服
 办公用品
 厨房用具
(3 rows)

shop=#

在使用 DISTINCT 时,NULL 也被视为一类数据。
NULL 存在于多行中时,也会被合并为一条 NULL 数据。
代码清单2-8 对含有NULL数据的列使用DISTINCT关键字

shop=# SELECT DISTINCT purchase_price FROM Product;
 purchase_price
----------------

            320
            500
           2800
           5000
            790
(6 rows)

shop=#

DISTINCT 在多列之前使用,会将多个列的数据进行组合,将重复的数据合并为一条。

代码清单2-9 在多列之前使用DISTINCT

shop=# SELECT DISTINCT product_type, regist_date FROM Product;
 product_type | regist_date
--------------+-------------
 衣服         |
 厨房用具     | 2008-04-28
 衣服         | 2009-09-20
 办公用品     | 2009-11-11
 厨房用具     | 2009-01-15
 办公用品     | 2009-09-11
 厨房用具     | 2009-09-20
(7 rows)

shop=#

注意:DISTINCT 关键字只能用在第一个列名之前。

注释的书写方法

一行注释 书写在 "--" 之后,只能写在同一行。
多行注释 书写在 "/*" 和 "*/" 之间,可以跨多行。

2-2 算数运算符与比较运算符

需要注意NULL

(1)包含NULL的运算,其结果也是NULL。
(2)不能对NULL使用比较运算符,判断是否为 NULL 使用 IS NULL 运算符

代码清单2-29 选取不为NULL的记录

shop=# SELECT product_name, purchase_price
shop-#  FROM Product
shop-#  WHERE purchase_price IS NULL;
 product_name | purchase_price
--------------+----------------
 叉子         |
 圆珠笔       |
(2 rows)

shop=#

2-3 逻辑运算符

含有NULL时的真值

Product表中设置NOT NULL约束的原因
原本只有 4 行的真值表,如果要考虑 NULL 的话就会像表 2-6 那样增加为3×3=9 行,考虑 NULL 时的条件判断也会变得异常复杂,数据库领域的有识之士们达成了“尽量不
使用 NULL”的共识。

3 聚合与排序

3-1 对表进行聚合查询

聚合函数

SQL中用于汇总的函数,eg: COUNT, SUM, AVG, MAX, MIN

计算NULL之外的数据的行数

COUNT(*)会得到包含NULL的数据行数,而COUNT(<列名>)会得到NULL之外的数据行数。

计算合计值

对于 SUM 函数来说,即使包含 NULL,也可以计算出合计值。
从结果上说,所有的聚合函数,如果以列名为参数,那么在计算之前就已经把NULL 排除在外了。因此,无论有多少个 NULL 都会被无视。

计算平均值

平均值的情况与 SUM 函数相同,会事先删除 NULL 再进行计算,注意分母也会去除 NULL 的行。NULL 被排除,这与“等价为 0”并不相同。

使用聚合函数删除重复值(关键字DISTINCT)

代码清单3-10 计算去除重复数据后的数据行数

shop=# SELECT COUNT(DISTINCT product_type) FROM Product;
 count
-------
     3
(1 row)

shop=# SELECT DISTINCT product_type FROM Product;
 product_type
--------------
 衣服
 办公用品
 厨房用具
(3 rows)

shop=#

注意:这时 DISTINCT 必须写在括号中。

不仅限于 COUNT 函数,所有的聚合函数都可以使用 DISTINCT。

3-2 对表进行分组

GROUP BY子句

语法3-1 使用GROUP BY子句进行汇总
SELECT <列名1>, <列名2>, <列名3>, …… 
 FROM <表名>
 GROUP BY <列名1>, <列名2>, <列名3>, ……

代码清单3-13 按照商品种类统计数据行数

SELECT product_type, COUNT(*) FROM Product GROUP BY product_type;

执行结果:

 product_type | count
--------------+-------
 衣服         |     2
 办公用品     |     2
 厨房用具     |     4
(3 rows)

GROUP BY 子句中指定的列称为聚合键或者分组列。

GROUP BY 子句也和 SELECT 子句一样, 可以通过逗号分隔指定多列。

shop=# SELECT product_type,regist_date, COUNT(*) FROM Product GROUP BY product_type, regist_date;
 product_type | regist_date | count
--------------+-------------+-------
 衣服         |             |     1
 厨房用具     | 2008-04-28  |     1
 衣服         | 2009-09-20  |     1
 办公用品     | 2009-11-11  |     1
 厨房用具     | 2009-01-15  |     1
 办公用品     | 2009-09-11  |     1
 厨房用具     | 2009-09-20  |     2
(7 rows)

shop=#

▲ 子句的书写顺序(暂定) 1. SELECT → 2. FROM → 3. WHERE → 4. GROUP BY

聚合键中包含NULL的情况

聚合键中包含NULL时,在结果中会以“不确定”行(空行)的形式表现出来。

使用WHERE子句时GROUP BY的执行结果

语法3-2 使用WHERE子句和GROUP BY子句进行汇总处理
SELECT <列名1>, <列名2>, <列名3>, ……
 FROM <表名>
 WHERE <条件表达式>
 GROUP BY <列名1>, <列名2>, <列名3>, ……;

GROUP BY 和 WHERE 并用时,SELECT 语句的执行顺序如下所示。

▲ GROUP BY 和 WHERE 并用时 SELECT 语句的执行顺序 FROM → WHERE → GROUP BY → SELECT

与聚合函数和GROUP BY子句有关的常见错误

常见错误① ——在SELECT子句中书写了多余的列
实际上,使用聚合函数时,SELECT 子句中只能存在以下三种元素。
- 常数
- 聚合函数
- GROUP BY子句中指定的列名(也就是聚合键)

常见错误② ——在GROUP BY子句中写了列的别名

代码清单3-17 GROUP BY子句中使用列的别名可能会引发错误

shop=# SELECT product_type AS pt, COUNT(*)
shop-#  FROM Product
shop-#  GROUP BY pt;
    pt    | count
----------+-------
 衣服     |     2
 办公用品 |     2
 厨房用具 |     4
(3 rows)

shop=#

SELECT 子句在 GROUP BY 子句之后执行。 在执行 GROUP BY 子句时,SELECT 子句中定义的别名,DBMS 还并不知道。

PostgreSQL 执行上述 SQL 语句并不会发生错误,但是这样的写法在其它 DBMS 中并不通用。

常见错误③——GROUP BY子句的结果能排序吗 --> 随机的

常见错误④——在WHERE子句中使用聚合函数 --> 使用HAVING

3-3 为聚合结果指定条件

重点:

- 使用COUNT函数等对表中数据进行汇总操作时,为其指定条件的不是WHERE子句,而是HAVING子句。
- 聚合函数可以在SELECT子句、HAVING子句和ORDER BY子句中使用。
- HAVING子句要写在GROUP BY子句之后。
- WHERE子句用来指定数据行的条件,HAVING子句用来指定分组的条件。

HAVING子句

语法3-3 HAVING子句
SELECT <列名1>, <列名2>, <列名3>, ……
 FROM <表名>
 GROUP BY <列名1>, <列名2>, <列名3>, ……
 HAVING <分组结果对应的条件>

▲ 使用 HAVING 子句时 SELECT 语句的顺序 SELECT → FROM → WHERE → GROUP BY → HAVING

代码清单3-20 从按照商品种类进行分组后的结果中,取出“包含的数据行数为2 行”的组

SELECT product_type, COUNT(*) FROM Product GROUP BY product_type HAVING COUNT(*) = 2;

HAVING子句的构成要素

HAVING 子句中能够使用的 3 种要素:
- 常数
- 聚合函数
- GROUP BY子句中指定的列名(即聚合键)

相对于HAVING子句, 更适合写在WHERE子句中的条件

有些条件既可以写在 HAVING 子句当中, 又可以写在 WHERE 子句当中。这些条件就是聚合键所对应的条件。 

代码清单3-25 将条件书写在HAVING子句中的情况

SELECT product_type, COUNT(*)
FROM Product
GROUP BY product_type
HAVING product_type = '衣服';

代码清单3-26 将条件书写在WHERE子句中的情况

SELECT product_type, COUNT(*)
FROM Product
WHERE product_type = '衣服'
GROUP BY product_type;

建议写在 WHERE 子句之中。

(1)WHERE 子句和 HAVING 子句的作用不同。
WHERE 子句 = 指定行所对应的条件
HAVING 子句 = 指定组所对应的条件

(2)通常情况下,为了得到相同的结果,将条件写在 WHERE 子句中要比写在 HAVING 子句中的处理速度更快,返回结果所需的时间更短。
使用 COUNT 函数等对表中的数据进行聚合操作时,DBMS 内部就会进行排序处理。通过 WHERE子句指定条件时,由于排序之前就对数据进行了过滤,因此能够减少排序的数据量。通过 HAVING 子句是在排序之后才对数据进行分组的。

3-4 对查询结果进行排序

ORDER BY子句

语法3-4 ORDER BY子句
SELECT <列名1>, <列名2>, <列名3>, ……
 FROM <表名>
 ORDER BY <排序基准列1>, <排序基准列2>, ……

▲ 子句的书写顺序 1. SELECT 子句 → 2. FROM 子句 → 3. WHERE 子句 → 4. GROUP BY 子句 → 5. HAVING 子句 → 6. ORDER BY 子句

指定升序或降序

代码清单3-29 按照销售单价由高到低(降序)进行排列

SELECT product_id, product_name, sale_price, purchase_price
FROM Product
ORDER BY sale_price DESC;

ASC 和 DESC 这两个关键字是以列为单位指定的,可以同时指定一个列为升序,指定其他列为降序;默认使用升序进行排序。

指定多个排序键

规则是优先使用左侧的键,如果该列存在相同值的话,再接着参考右侧的键。

NULL的顺序

使用含有 NULL 的列作为排序键时,NULL 会在结果的开头或末尾汇总显示。

在排序键中使用显示用的别名

代码清单3-32 ORDER BY子句中可以使用列的别名

SELECT product_id AS id, product_name, sale_price AS sp, purchase_price
FROM Product
ORDER BY sp, id;

不能在 GROUP BY 子句中使用的别名,为什么可以在 ORDER BY子句中使用呢?
▲使用 HAVING 子句时 SELECT 语句的顺序
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY
这只是一个粗略的总结,具体的执行顺序根据 DBMS 的不同而不同
SELECT 子句的执行顺序在 GROUP BY 子句之后,ORDER BY 子句之前。因此,在执行 GROUP BY 子句时,SELECT 语句中定义的别名无法被识别。

ORDER BY子句中可以使用的列

ORDER BY子句中可以使用SELECT子句中未使用的列和聚合函数。

代码清单3-34 ORDER BY子句中也可以使用聚合函数

SELECT product_type, COUNT(*)
FROM Product
GROUP BY product_type
ORDER BY COUNT(*);

4 数据更新

4-1 数据的插入(INSERT语句的使用方法)

重点:
- 使用INSERT语句可以向表中插入数据(行)。原则上,INSERT语句每次执行一行数据的插入。
- 将列名和值用逗号隔开,分别括在()内,这种形式称为清单。
- 对表中所有列进行INSERT操作时可以省略表名后的列清单。
- 插入NULL时需要在VALUES子句的值清单中写入NULL。
- 可以为表中的列设定默认值(初始值),默认值可以通过在CREATE TABLE语句中为列设置DEFAULT约束来设定。
- 插入默认值可以通过两种方式实现,即在INSERT语句的VALUES子句中指定DEFAULT关键字(显式方法),或省略列清单(隐式方法)。
- 使用INSERT…SELECT可以从其他表中复制数据。

INSERT语句的基本语法

语法4-1 INSERT语句
INSERT INTO <表名> (列1, 列2, 列3, ……) VALUES (值1, 值2, 值3, ……);

ProductIns建表语句

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));

列清单的省略

对表进行全列 INSERT 时,可以省略表名后的列清单。

-- 包含列清单
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 ('0006', '高压锅', '厨房用具', 6800, 5000, '2009-01-15');

插入NULL

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

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

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

注意:想要插入 NULL 的列一定不能设置 NOT NULL 约束

插入默认值

可以通过在创建表的CREATE TABLE 语句中设置 DEFAULT 约束来设定默认值。

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

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

如果在创建表的同时设定了默认值,就可以在 INSERT 语句中自动为列赋值了。
(1)通过显式方法插入默认值

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

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

(2)通过隐式方法插入默认值
插入默认值时也可以不使用 DEFAULT 关键字,只要在列清单和VALUES 中省略设定了默认值的列就可以了。
代码清单4-7 通过隐式方法设定默认值

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

执行结果:

shop=# SELECT * FROM ProductIns;
 product_id | product_name | product_type | sale_price | purchase_price | regist_date
------------+--------------+--------------+------------+----------------+-------------
 0005       | 高压锅       | 厨房用具     |       6800 |           5000 | 2009-01-15
 0006       | 高压锅       | 厨房用具     |       6800 |           5000 | 2009-01-15
 0007       | 叉子         | 厨房用具     |        500 |                | 2009-09-20
 0008       | 擦菜板       | 厨房用具     |          0 |            790 | 2009-04-28
 0009       | 擦菜板       | 厨房用具     |          0 |            790 | 2009-04-28
(5 rows)

shop=#

从其它表中复制数据

要插入数据,除了使用 VALUES 子句指定具体的数据之外,还可以从其它表中复制数据。

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

-- 用来插入数据的商品复制表
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));

代码清单4-10 INSERT ... SELECT语句

-- 将商品表中的数据复制到商品复制表中
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语句中,可以使用WHERE子句或者GROUP BY子句等SQL语法

代码清单4-11 创建ProductType表的CREATE TABLE语句
该表是用来存储根据商品种类(product_type)计算出的销售单价合计值以及进货单价合计值的表

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

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

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;

执行结果:

shop=# SELECT * FROM ProductType;
 product_type | sum_sale_price | sum_purchase_price
--------------+----------------+--------------------
 衣服         |           5000 |               3300
 办公用品     |            600 |                320
 厨房用具     |          11180 |               8590
(3 rows)

shop=#

4-2 数据的删除(DELETE语句的使用方法)

DELETE语句的基本语法

语法4-2 保留数据表,仅删除全部数据行的DELETE语句
DELETE FROM <表名>;

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

语法4-3 删除部分数据行的搜索型DELETE
DELETE FROM <表名> WHERE <条件>;

删除和舍弃

标准 SQL 中用来从表中删除数据的只有 DELETE 语句。但是,很多数据库产品中还存在另外一种被称为 TRUNCATE 的语句。

语法4-A 只能删除表中全部数据的TRUNCATE语句
TRUNCATE <表名>;
与 DELETE 不同的是,TRUNCATE 只能删除表中的全部数据。其处理速度比 DELETE 要快得多。因此需要删除全部数据行时,使用 TRUNCATE 可以缩短执行时间。

4-3 数据的更新(UPDATE语句的使用方法)

UPDATE语句的基本语法

语法4-4 改变表中数据的UPDATE语句
UPDATE <表名>  SET <列名> = <表达式>;

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

语法4-5 更新部分数据行的搜索型UPDATE
UPDATE <表名>  SET <列名> = <表达式> WHERE <条件>;

使用NULL进行更新

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

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

UPDATE Product SET regist_date = NULL WHERE product_id = '0008';

注意:只有未设置 NOT NULL 约束和主键约束的列才可以清空为NULL。

多列更新

方法①:代码清单4-19

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

方法②:代码清单4-20

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

4-4 事务

事务就是需要在同一个处理单元中执行的一系列更新处理的集合。

创建事务

如果想在 DBMS 中创建事务,可以按照如下语法结构编写 SQL 语句。
语法4-6 事务的语法

事务开始语句;
 DML语句①;
 DML语句②;
 DML语句③;
 . . .
事务结束语句(COMMIT或者ROLLBACK);

代码清单4-21 更新商品信息的事务
SQL Server PostgreSQL

BEGIN TRANSACTION;
 -- 将运动T恤的销售单价降低1000日元
 UPDATE Product
 SET sale_price = sale_price - 1000
 WHERE product_name = '运动T恤';
 -- 将T恤衫的销售单价上浮1000日元
 UPDATE Product
 SET sale_price = sale_price + 1000
 WHERE product_name = 'T恤衫';
COMMIT;

MySQL

START TRANSACTION;
 -- 将运动T恤的销售单价降低1000日元
 UPDATE Product
 SET sale_price = sale_price - 1000
 WHERE product_name = '运动T恤';
 -- 将T恤衫的销售单价上浮1000日元
 UPDATE Product
 SET sale_price = sale_price + 1000
 WHERE product_name = 'T恤衫';
COMMIT;

Oracle DB2

-- 将运动T恤的销售单价降低1000日元
UPDATE Product
 SET sale_price = sale_price - 1000
 WHERE product_name = '运动T恤';
 -- 将T恤衫的销售单价上浮1000日元
UPDATE Product
 SET sale_price = sale_price + 1000
 WHERE product_name = 'T恤衫';
COMMIT;

COMMIT  提交处理
ROLLBACK  取消处理

ACID特性

原子性(Atomicity)
原子性是指在事务结束时,其中所包含的更新处理要么全部执行,要么完全不执行,也就是要么占有一切要么一无所有。

一致性(Consistency)
一致性也称为完整性。一致性指的是事务中包含的处理要满足数据库提前设置的约束,如主键约束或者 NOT NULL 约束等。例如,设置了 NOT NULL 约束的列是不能更新为 NULL 的,试图插入违反主键约束的记录就会出错,无法执行。对事务来说,这些不合法的 SQL 会被回滚。

隔离性(Isolation)
隔离性指的是保证不同事务之间互不干扰的特性。

持久性(Durability)
持久性也可以称为耐久性,指的是在事务(不论是提交还是回滚)结束后,DBMS 能够保证该时间点的数据状态会被保存的特性。即使由于系统故障导致数据丢失,数据库也一定能通过某种手段进行恢复。
保证持久性的方法根据实现的不同而不同,其中最常见的就是将事务的执行记录保存到硬盘等存储介质中(该执行记录称为日志)。当发生故障时,可以通过日志恢复到故障发生前的状态。

附:

法则 2-1 星号(*)代表全部列的意思。
法则 2-2 设定汉语别名时需要使用双引号(")括起来。
法则 2-3 在SELECT语句中使用DISTINCT可以删除重复行。
法则 2-4 WHERE子句要紧跟在FROM子句之后。
法则 2-8 字符串类型的数据原则上按照字典顺序进行排序,不能与数字的大小顺序混淆。
法则 2-9 希望选取NULL记录时,需要在条件表达式中使用IS NULL运算符。希望选取不是NULL的记录时,需要在条件表达式中使用IS NOT NULL运算符。
法则 2-11 多个查询条件进行组合时,需要使用AND运算符或者OR运算符。
法则 2-13 AND运算符的优先级高于OR运算符。想要优先执行OR运算符时可以使用括号。

法则 3-1  COUNT函数的结果根据参数的不同而不同。COUNT(*)会得到包含NULL的数据行数,而COUNT(<列名>)会得到NULL之外的数据行数。
法则 3-2 聚合函数会将NULL排除在外。但COUNT(*)例外,并不会排除NULL。
法则 3-3 MAX/MIN函数几乎适用于所有数据类型的列。SUM/AVG函数只适用于数值类型的列。
法则 3-4 想要计算值的种类时,可以在COUNT函数的参数中使用DISTINCT。
法则 3-5 在聚合函数的参数中使用DISTINCT,可以删除重复数据。
法则 3-6 GROUP BY就像是切分表的一把刀。
法则 3-7 SQL子句的顺序不能改变,也不能互相替换。
法则 3-8 聚合键中包含NULL时,在结果中会以“不确定”行(空行)的形式表现出来。
法则 3-9 使用GROUP BY子句时,SELECT子句中不能出现聚合键之外的列名。
法则 3-10 在GROUP BY子句中不能使用SELECT子句中定义的别名。
法则 3-11 GROUP BY子句结果的显示是无序的。
法则 3-12 只有SELECT子句和HAVING子句(以及ORDER BY子句)中能够使用聚合函数。
法则 3-13 HAVING子句要写在GROUP BY子句之后。
法则 3-14 聚合键所对应的条件不应该书写在HAVING子句当中,而应该书写在WHERE子句当中。
法则 3-15 ORDER BY子句通常写在SELECT语句的末尾。
法则 3-16 未指定ORDER BY子句中排列顺序时会默认使用升序进行排列。
法则 3-17 排序键中包含NULL时,会在开头或末尾进行汇总。
法则 3-18 在ORDER BY子句中可以使用SELECT子句中定义的别名。
法则 3-19 在ORDER BY子句中可以使用SELECT子句中未使用的列和聚合函数。

法则 4-2 省略INSERT语句中的列名,就会自动设定为该列的默认值(没有默认值时会设定为NULL)。
法则 4-3 INSERT语句的SELECT语句中,可以使用WHERE子句或者GROUP BY子句等任何 SQL语法(但使用ORDER BY子句并不会产生任何效果)。
法则 4-4 DELETE语句的删除对象并不是表或者列,而是记录(行)
法则 4-6 使用UPDATE语句可以将值清空为NULL(但只限于未设置NOT NULL约束的列)。
法则 4-7 事务是需要在同一个处理单元中执行的一系列更新处理的集合。
法则 4-8 虽然我们可以不清楚事务开始的时间点,但是在事务结束时一定要仔细进行确认。
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值