Wonderful Sql
一. 初识数据库
练习题
1.1 编写一条 CREATE TABLE 语句,用来创建一个包含表 1-A 中所列各项的表 Addressbook (地址簿),并为 regist_no (注册编号)列设置主键约束
表1-A 表 Addressbook (地址簿)中的列
DROP TABLE IF EXISTS Adressbook;
CREATE TABLE Adressbook
(regist_no INTEGER NOT NULL,
name VARCHAR(128) NOT NULL,
adress VARCHAR(256) NOT NULL,
tel_no CHAR(10),
mail_adress CHAR(20),
PRIMARY KEY (regist_no));
DESC Adressbook;
Field | Type | Null | Key | Default | Extra | |
---|---|---|---|---|---|---|
0 | regist_no | int(11) | NO | PRI | None | |
1 | name | varchar(128) | NO | None | ||
2 | adress | varchar(256) | NO | None | ||
3 | tel_no | char(10) | YES | None | ||
4 | mail_adress | char(20) | YES | None |
1.2 假设在创建练习1.1中的 Addressbook 表时忘记添加如下一列 postal_code (邮政编码)了,请编写 SQL 把此列添加到 Addressbook 表中。
列名 : postal_code
数据类型 :定长字符串类型(长度为 8)
约束 :不能为 NULL
ALTER TABLE Adressbook ADD COLUMN postal_code CHAR(8) NOT NULL;
Field | Type | Null | Key | Default | Extra | |
---|---|---|---|---|---|---|
0 | regist_no | int(11) | NO | PRI | None | |
1 | name | varchar(128) | NO | None | ||
2 | adress | varchar(256) | NO | None | ||
3 | tel_no | char(10) | YES | None | ||
4 | mail_adress | char(20) | YES | None | ||
5 | postal_code | char(8) | NO | None |
1.3 填空题
请补充如下 SQL 语句来删除 Addressbook 表。
( ) table Addressbook;
DROP table Addressbook;
1.4 判断题
是否可以编写 SQL 语句来恢复删除掉的 Addressbook 表?
不使用工具无法恢复,只能通过运行建表语句重新创建
二. 基础查询与排序
练习题 - 第一部分
2.1 编写一条SQL语句,从 product
(商品) 表中选取出“登记日期(regist_date
)在2009年4月28日之后”的商品,查询结果要包含 product name
和 regist_date
两列。
SELECT product_name, regist_date
FROM product
WHERE regist_date > '2009-04-28';
product_name | regist_date | |
---|---|---|
0 | T恤 | 2009-09-20 |
1 | 打孔器 | 2009-09-11 |
2 | 菜刀 | 2009-09-20 |
3 | 叉子 | 2009-09-20 |
4 | 圆珠笔 | 2009-11-11 |
2.2 请说出对product 表执行如下3条SELECT语句时的返回结果。
①
SELECT *
FROM product
WHERE purchase_price = NULL;
②
SELECT *
FROM product
WHERE purchase_price <> NULL;
③
SELECT *
FROM product
WHERE product_name > NULL;
①
product_id | product_name | product_type | sale_price | purchase_price | regist_date |
---|
②
product_id | product_name | product_type | sale_price | purchase_price | regist_date |
---|
③
product_id | product_name | product_type | sale_price | purchase_price | regist_date |
---|
2.3 2.2.3章节中的SELECT语句能够从
product 表中取出“销售单价(
sale_price)比进货单价(
purchase_price`)高出500日元以上”的商品。请写出两条可以得到相同结果的SELECT语句。执行结果如下所示:
product_name | sale_price | purchase_price
-------------+------------+------------
T恤衫 | 1000 | 500
运动T恤 | 4000 | 2800
高压锅 | 6800 | 5000
SELECT product_name, sale_price, purchase_price
FROM product
WHERE sale_price - purchase_price >= 500;
SELECT product_name, sale_price, purchase_price
FROM product
WHERE sale_price >= purchase_price + 500;
2.4 请写出一条SELECT语句,从 product
表中选取出满足“销售单价打九折之后利润高于 100
日元的办公用品和厨房用具”条件的记录。查询结果要包括 product_name
列、product_type
列以及销售单价打九折之后的利润(别名设定为 profit
)。
提示:销售单价打九折,可以通过 sale_price
列的值乘以0.9获得,利润可以通过该值减去 purchase_price
列的值获得。
SELECT product_name, product_type,
sale_price * 0.9 - purchase_price AS profit
FROM product
WHERE sale_price * 0.9 - purchase_price > 100
AND ( product_type = '办公用品'
OR product_type = '厨房用具');
product_name | product_type | profit | |
---|---|---|---|
0 | 打孔器 | 办公用品 | 130.0 |
1 | 高压锅 | 厨房用具 | 1120.0 |
练习题 - 第二部分
2.5 请指出下述SELECT语句中所有的语法错误。
SELECT product_id, SUM(product_name)
--本SELECT语句中存在错误。
FROM product
GROUP BY product_type
WHERE regist_date > '2009-09-01';
① SUM
函数仅适用于数字类型的字段, 不能对product_name
使用SUM
聚合
② SELECT
子句中的product_id
字段为非聚合函数, 不在GROUP BY
的字段列表product_type
内
③ WHERE
子句应该出现在GROUP BY
之前, FROM
之后
2.6 请编写一条SELECT语句,求出销售单价( sale_price
列)合计值大于进货单价( purchase_price
列)合计值1.5倍的商品种类。执行结果如下所示。
product_type | sum | sum
-------------+------+------
衣服 | 5000 | 3300
办公用品 | 600 | 320
SELECT product_type, SUM(sale_price), SUM(purchase_price)
FROM product
GROUP BY product_type
HAVING SUM(sale_price) > SUM(purchase_price) * 1.5;
product_type | SUM(sale_price) | SUM(purchase_price) | |
---|---|---|---|
0 | 衣服 | 5000.0 | 3300.0 |
1 | 办公用品 | 600.0 | 320.0 |
2.7 此前我们曾经使用SELECT语句选取出了product(商品)表中的全部记录。当时我们使用了 ORDER BY
子句来指定排列顺序,但现在已经无法记起当时如何指定的了。请根据下列执行结果,思考 ORDER BY
子句的内容。
SELECT *
FROM product
ORDER BY regist_date IS NOT NULL, regist_date DESC, sale_price;
product_id | product_name | product_type | sale_price | purchase_price | regist_date | |
---|---|---|---|---|---|---|
0 | 0003 | 运动T恤 | 衣服 | 4000 | 2800.0 | None |
1 | 0008 | 圆珠笔 | 办公用品 | 100 | NaN | 2009-11-11 |
2 | 0006 | 叉子 | 厨房用具 | 500 | NaN | 2009-09-20 |
3 | 0001 | T恤 | 衣服 | 1000 | 500.0 | 2009-09-20 |
4 | 0004 | 菜刀 | 厨房用具 | 3000 | 2800.0 | 2009-09-20 |
5 | 0002 | 打孔器 | 办公用品 | 500 | 320.0 | 2009-09-11 |
6 | 0005 | 高压锅 | 厨房用具 | 6800 | 5000.0 | 2009-01-15 |
7 | 0007 | 擦菜板 | 厨房用具 | 880 | 790.0 | 2008-04-28 |
三. 复杂一点的查询
练习题 - 第一部分
3.1 创建出满足下述三个条件的视图(视图名称为 ViewPractice5_1)。使用 product(商品)表作为参照表,假设表中包含初始状态的 8 行数据。
- 条件 1:销售单价大于等于 1000 日元。
- 条件 2:登记日期是 2009 年 9 月 20 日。
- 条件 3:包含商品名称、销售单价和登记日期三列。
对该视图执行 SELECT 语句的结果如下所示。
SELECT * FROM ViewPractice5_1;
执行结果
product_name | sale_price | regist_date
-------------+------------+------------
T恤 | 1000 | 2009-09-20
菜刀 | 3000 | 2009-09-20
CREATE VIEW ViewPractice5_1 (product_name, sale_price, regist_date) AS
SELECT product_name, sale_price, regist_date
FROM product
WHERE sale_price >= 1000
AND regist_date='2009-09-20';
SELECT * FROM ViewPractice5_1;
product_name | sale_price | regist_date | |
---|---|---|---|
0 | T恤 | 1000 | 2009-09-20 |
1 | 菜刀 | 3000 | 2009-09-20 |
3.2 向习题一中创建的视图 ViewPractice5_1
中插入如下数据,会得到什么样的结果?为什么?
INSERT INTO ViewPractice5_1 VALUES (' 刀子 ', 300, '2009-11-02');
# | Time | Action | Message | Duration / Fetch |
---|---|---|---|---|
1 | 0 | 00:38:48 | INSERT INTO ViewPractice5_1 VALUES (’ 刀子 ', 300, ‘2009-11-02’) Error Code: 1423. Field of view ‘shop.viewpractice5_1’ underlying table doesn’t have a default value | 0.000 sec |
查询结果会报错, 由于视图只是原表的一个窗口, 视图中的字段与原表不重合, 原表中有NOT NULL的字段没有给默认值导致报错, 只有插入命令对原表能插入成功时, 才能对视图插入成功
3.3 请根据如下结果编写 SELECT 语句,其中 sale_price_avg 列为全部商品的平均销售单价。
SELECT product_id, product_name, product_type, sale_price,
(SELECT AVG(sale_price) FROM product) AS sale_price_avg
FROM product;
product_id | product_name | product_type | sale_price | sale_price_avg | |
---|---|---|---|---|---|
0 | 0001 | T恤 | 衣服 | 1000 | 2097.5 |
1 | 0002 | 打孔器 | 办公用品 | 500 | 2097.5 |
2 | 0003 | 运动T恤 | 衣服 | 4000 | 2097.5 |
3 | 0004 | 菜刀 | 厨房用具 | 3000 | 2097.5 |
4 | 0005 | 高压锅 | 厨房用具 | 6800 | 2097.5 |
5 | 0006 | 叉子 | 厨房用具 | 500 | 2097.5 |
6 | 0007 | 擦菜板 | 厨房用具 | 880 | 2097.5 |
7 | 0008 | 圆珠笔 | 办公用品 | 100 | 2097.5 |
3.4 请根据习题一中的条件编写一条 SQL 语句,创建一幅包含如下数据的视图(名称为AvgPriceByType)。
提示:其中的关键是 sale_price_avg_type
列。与习题三不同,这里需要计算出的 是各商品种类的平均销售单价。这与使用关联子查询所得到的结果相同。 也就是说,该列可以使用关联子查询进行创建。问题就是应该在什么地方使用这个关联子查询。
CREATE VIEW AvgPriceByType AS
SELECT product_id, product_name, product_type, sale_price,
(SELECT AVG(sale_price)
FROM product AS p2
WHERE p1.product_type=p2.product_type) AS sale_price_avg
FROM product AS p1;
SELECT * FROM AvgPriceByType;
product_id | product_name | product_type | sale_price | sale_price_avg | |
---|---|---|---|---|---|
0 | 0001 | T恤 | 衣服 | 1000 | 2500.0 |
1 | 0002 | 打孔器 | 办公用品 | 500 | 300.0 |
2 | 0003 | 运动T恤 | 衣服 | 4000 | 2500.0 |
3 | 0004 | 菜刀 | 厨房用具 | 3000 | 2795.0 |
4 | 0005 | 高压锅 | 厨房用具 | 6800 | 2795.0 |
5 | 0006 | 叉子 | 厨房用具 | 500 | 2795.0 |
6 | 0007 | 擦菜板 | 厨房用具 | 880 | 2795.0 |
7 | 0008 | 圆珠笔 | 办公用品 | 100 | 300.0 |
练习题 - 第二部分
3.5 判断题
四则运算中含有 NULL 时(不进行特殊处理的情况下),运算结果是否必然会变为NULL ?
是
3.6 对本章中使用的 product
(商品)表执行如下 2 条 SELECT
语句,能够得到什么样的结果呢?
①
SELECT product_name, purchase_price
FROM product
WHERE purchase_price NOT IN (500, 2800, 5000);
②
SELECT product_name, purchase_price
FROM product
WHERE purchase_price NOT IN (500, 2800, 5000, NULL);
product_name | purchase_price | |
---|---|---|
0 | 打孔器 | 320 |
1 | 擦菜板 | 790 |
product_name | purchase_price |
---|
IN或NOT IN谓词无法选取NULL的数据,也无法与NULL作比较,可以使用特定的谓词IS NULL或IS NOT NULL搭配逻辑运算符实现
3.7 按照销售单价( sale_price
)对练习 3.6 中的 product
(商品)表中的商品进行如下分类。
- 低档商品:销售单价在1000日元以下(T恤衫、办公用品、叉子、擦菜板、 圆珠笔)
- 中档商品:销售单价在1001日元以上3000日元以下(菜刀)
- 高档商品:销售单价在3001日元以上(运动T恤、高压锅)
请编写出统计上述商品种类中所包含的商品数量的 SELECT 语句,结果如下所示。
执行结果
low_price | mid_price | high_price
----------+-----------+------------
5 | 1 | 2
SELECT SUM(CASE WHEN sale_price <= 1000 THEN 1 ELSE 0 END) AS low_price,
SUM(CASE WHEN sale_price BETWEEN 1001 AND 3000 THEN 1 ELSE 0 END) AS mid_price,
SUM(CASE WHEN sale_price >= 3001 THEN 1 ELSE 0 END) AS high_price
FROM product;
low_price | mid_price | high_price | |
---|---|---|---|
0 | 5.0 | 1.0 | 2.0 |