数据库习题
每一章的习题都在这里。
1
编写语句从Customers表中检索所有的ID(cust_id)。
SELECT cust_id
FROM Customers;
2
OrderItems 表包含了所有已订购的产品(有些已经被订购多次)。编写SQL 语句,检索并列出已订购产品(prod_id)的清单(不用列每个订单,只列出不同产品的清单)。提示:最终应该显示 7 行。
SELECT DISTINCT Prod_id
FROM OrderItems;
3
编写 SQL语句,检索 Customers 表中所有的列,再编写另外的 SELECT语句,仅检索顾客的 ID。使用注释,注释掉一条 SELECT 语句,以便运行另一条 SELECT 语句。(当然,要测试这两个语句。)
/*SELECT *
FROM Customers;*/
SELECT cust_id
FROM Customers;
4
编写 SQL 语句,从 Customers 中检索所有的顾客名称(cust_names),并按从 Z 到 A 的顺序显示结果。
SELECT cust_names
FROM Customers
ORDER BY cust_name DESC;
5
编写 SQL 语句,从 Orders 表中检索顾客 ID(cust_id)和订单号(order_num),并先按顾客 ID 对结果进行排序,再按订单日期倒序排列。
SELECT cust_id, order_num
FROM Orders
ORDER BY cust_id, order_date DESC;
6
显然,我们的虚拟商店更喜欢出售比较贵的物品,而且这类物品有很多。编写 SQL 语句,显示 OrderItems 表中的数量和价格(item_price),并按数量由多到少、价格由高到低排序。
SELECT quantity, item_price
FROM OrderItems
ORDER BY quantity DESC , item_price DESC;
7
下面的 SQL 语句有问题吗?(尝试在不运行的情况下指出。)
SELECT vend_name,
FROM Vendors
ORDER vend_name DESC;
少了一个BY
。
8
编写 SQL 语句,从 Products 表中检索产品 ID(prod_id)和产品名称(prod_name),只返回价格为 9.49 美元的产品。
SELECT prod_id, prod_name
FROM Products
WHERE prod_price = 9.49;
9
编写 SQL 语句,从 Products 表中检索产品 ID(prod_id)和产品名称(prod_name),只返回价格为 9 美元或更高的产品。
SELECT prod_id, prod_name
FROM Products
WHERE prod_price >= 9;
10
编写 SQL 语句,从 OrderItems 表中检索出所有不同订单号(order_num),其中包含 100 个或更多的产品。
SELECT DISTINCT order_num
FROM OrderItems
WHERE quantity >=100;
11
编写 SQL 语句,返回 Products 表中所有价格在 3 美元到 6 美元之间的产品的名称(prod_name)和价格(prod_price),然后按价格对结果进行排序。
SELECT prod_name, prod_price
FROM Products
WHERE prod_price BETWEEN 3 AND 6
ORDER BY prod_price;
12
编写 SQL 语句,从 Vendors 表中检索供应商名称(vend_name),仅返回加利福尼亚州的供应商(这需要按国家[USA]和州[CA]进行过滤,没准其他国家也存在一个加利福尼亚州)。提示:过滤器需要匹配字符串。
SELECT vend_name
FROM Vendors
WHERE vend_country = 'USA' AND vend_state = 'CA';
13
编写 SQL 语句,查找所有至少订购了总量 100 个的 BR01、BR02 或BR03 的订单。你需要返回 OrderItems 表的订单号(order_num)、产品 ID(prod_id)和数量,并按产品 ID 和数量进行过滤。提示:根据编写过滤器的方式,可能需要特别注意求值顺序。
SELECT order_num, prod_id
FROM OrderItems
WHERE quantity >= 100 AND prod_id = 'BR01' OR prod_id = 'BR02' OR prod_id = 'BR03';
14
回顾11题,编写 SQL 语句,返回所有价格在 3美元到 6美元之间的产品的名称(prod_name)和价格(prod_price)。使用 AND,然后按价格对结果进行排序。
SELECT prod_name, prod_price
FROM Products
WHERE prod_price = 3 AND prod_price = 6
ORDER BY prod_price;
15
下面的 SQL 语句有问题吗?(尝试在不运行的情况下指出。)
SELECT vend_name
FROM Vendors
ORDER BY vend_name
WHERE vend_country = 'USA' AND vend_state = 'CA';
ORDER BY
子句应该写在最后面。
16
编写 SQL 语句,从 Products 表中检索产品名称(prod_name)和描述(prod_desc),仅返回描述中包含 toy 一词的产品。
SELECT prod_name, prod_desc
FROM Products
WHERE prod_desc LIKE '%toy%';
17
反过来再来一次。编写 SQL 语句,从 Products 表中检索产品名称(prod_name)和描述(prod_desc),仅返回描述中未出现 toy 一词的产品。这次,按产品名称对结果进行排序。
SELECT prod_name, prod_desc
FROM Products
WHERE prod_desc NOT LIKE '%toy%';
18
编写 SQL 语句,从 Products 表中检索产品名称(prod_name)和描述(prod_desc),仅返回描述中同时出现 toy 和 carrots 的产品。有好几种方法可以执行此操作,但对于这个挑战题,请使用 AND 和两个 LIKE 比较。
SELECT prod_name, prod_desc
FROM Products
WHERE Products NOT LIKE '%toy%' AND Products NOT LIKE '%carrots%';
19
编写 SQL 语句,从 Products 表中检索产品名称(prod_name)和描述(prod_desc),仅返回在描述中以先后顺序同时出现 toy 和 carrots 的产品。提示:只需要用带有三个 % 符号的 LIKE 即可。
SELECT prod_name, prod_desc
FROM Products
WHERE prod_desc LIKE '%toy%carrots%';
20
别名的常见用法是在检索出的结果中重命名表的列字段(为了符合特定的报表要求或客户需求)。编写 SQL 语句,从 Vendors 表中检索vend_id、vend_name、vend_address 和 vend_city,将 vend_name 重命名为 vname,将 vend_city 重命名为 vcity,将 vend_address重命名为 vaddress。按供应商名称对结果进行排序(可以使用原始名称或新的名称)。
SELECT vend_id, vend_name AS vname, vend_city AS vcity, vend_address AS vaddress
FROM Vendors
ORDER BY vend_name;
21
我们的示例商店正在进行打折促销,所有产品均降价 10%。编写 SQL语句,从 Products 表中返回 prod_id、prod_price 和 sale_price。sale_price 是一个包含促销价格的计算字段。提示:可以乘以 0.9,得到原价的 90%(即 10%的折扣)。
SELECT prod_id, prod_price, prod_price * 0.9 AS sale_price
FROM Products;
22
我们的商店已经上线了,正在创建顾客账户。所有用户都需要登录名,默认登录名是其名称和所在城市的组合。编写 SQL 语句,返回顾客 ID(cust_id)、顾客名称(customer_name)和登录名(user_login),其中登录名全部为大写字母,并由顾客联系人的前两个字符(cust_contact)和其所在城市的前三个字符(cust_city)组成。例如,我的登录名是 BEOAK(Ben Forta,居住在 Oak Park)。提示:需要使用函数、拼接和别名。
SELECT cust_id, customer_name, UPPER(LEFT(cust_contact,2) + LEFT(cust_city,3)) AS user_login
FROM Customers;
23
编写 SQL 语句,返回 2020 年 1 月的所有订单的订单号(order_num)和订单日期(order_date),并按订单日期排序。你应该能够根据目前已学的知识来解决此问题,但也可以开卷查阅 DBMS 文档。
SELECT order_num, order_date
FROM Orders
WHERE DATEPART(yy,order_date) = 2020 AND DATEPART (mm,order_date) = 1
ORDER BY order_date;
24
编写 SQL 语句,确定已售出产品的总数(使用 OrderItems 中的quantity 列)。
SELECT sum(quantity)
FROM OrderItems;
25
修改刚刚创建的语句,确定已售出产品项(prod_id)BR01 的总数。
SELECT sum(quantity)
FROM OrderItems
WHERE prod_id = 'BR01';
26
编写 SQL 语句,确定 Products 表中价格不超过 10 美元的最贵产品的价格(prod_price)。将计算所得的字段命名为 max_price。
SELECT MAX(prod_price) AS max_price
FROM Products
WHERE prod_price <= 10;
27
OrderItems 表包含每个订单的每个产品。编写 SQL 语句,返回每个订单号(order_num)各有多少行数(order_lines),并按 order_lines对结果进行排序。
SELECT order_num, COUNT(order_num) AS order_lines
FROM OrderItems
GROUP BY order_num
ORDER BY order_lines;
28
编写 SQL 语句,返回名为 cheapest_item 的字段,该字段包含每个供应商成本最低的产品(使用 Products 表中的 prod_price),然后从最低成本到最高成本对结果进行排序。
SELECT min(prod_price) AS cheapest_item
FROM Products
GROUP BY vend_id
ORDER BY cheapest_item;
29
确定最佳顾客非常重要,请编写 SQL 语句,返回至少含 100 项的所有订单的订单号(OrderItems 表中的 order_num)。
SELECT order_num
FROM OrderItems
GROUP BY order_num
HAVING sum(quantity) >= 100;
30
确定最佳顾客的另一种方式是看他们花了多少钱。编写 SQL 语句,返回总价至少为 1000 的所有订单的订单号(OrderItems 表中的order_num)。提示:需要计算总和(item_price 乘以 quantity)。按订单号对结果进行排序。
SELECT order_num, sum(item_price * quantity)
FROM OrderItems
GROUP BY order_num
HAVING sum(item_price * quantity) >= 1000;
31
下面的 SQL 语句有问题吗?(尝试在不运行的情况下指出。)
SELECT order_num, COUNT(*) AS items
FROM OrderItems
GROUP BY items
HAVING COUNT(*) >= 3
ORDER BY items, order_num;
GROUP BY
后面不应该是别名
32
使用子查询,返回购买价格为 10 美元或以上产品的顾客列表。你需要使用 OrderItems 表查找匹配的订单号(order_num),然后使用Order 表检索这些匹配订单的顾客 ID(cust_id)。
SELECT cust_id
FROM Orders
WHERE order_num IN (SELECT order_num
FROM OrderItems
WHERE item_price >= 10);
33
你想知道订购 BR01 产品的日期。编写 SQL 语句,使用子查询来确定哪些订单(在 OrderItems 中)购买了 prod_id 为 BR01 的产品,然后从 Orders 表中返回每个产品对应的顾客 ID(cust_id)和订单日期(order_date)。按订购日期对结果进行排序。
SELECT cust_id, order_date
FROM Orders
WHERE order_num IN (SELECT order_num
FROM OrderItems
WHERE prod_id = 'BR01');
34
现在我们让它更具挑战性。在上一个挑战题,返回购买 prod_id 为BR01 的产品的所有顾客的电子邮件(Customers 表中的 cust_email)。提示:这涉及 SELECT 语句,最内层的从 OrderItems 表返回 order_num,中间的从 Customers 表返回 cust_id。
SELECT cust_id, order_date, (SELECT cust_email
FROM Customers
WHERE cust_id = Orders.cust_id) AS Cemail
FROM Orders
WHERE order_num IN (SELECT order_num
FROM OrderItems
WHERE prod_id = 'BR01');
35
我们需要一个顾客 ID 列表,其中包含他们已订购的总金额。编写 SQL语句,返回顾客 ID(Orders 表中的 cust_id),并使用子查询返回total_ordered 以便返回每个顾客的订单总数。将结果按金额从大到小排序。提示:你之前已经使用 SUM()计算订单总数。
SELECT cust_id, sum(quantity * item_price) AS total_ordered
FROM Orders,OrderItems
WHERE Orders.order_num = OrderItems.order_num
GROUP BY cust_id
ORDER BY total_ordered DESC;
36
再来。编写 SQL 语句,从 Products 表中检索所有的产品名称(prod_name),以及名为 quant_sold 的计算列,其中包含所售产品的总数(在 OrderItems 表上使用子查询和 SUM(quantity)检索)。
SELECT prod_name, (SELECT SUM(quantity)
FROM OrderItems
WHERE Products.prod_id = OrderItems.prod_id) AS quant_sold
FROM Products;
37
编写 SQL 语句,返回 Customers 表中的顾客名称(cust_name)和Orders 表中的相关订单号(order_num),并 按顾客名称再按订单号对结果进行排序。实际上是尝试两次,一次使用简单的等联结语法,一次使用 INNER JOIN。
(1)
SELECT cust_name, order_num
FROM Customers, Orders
WHERE Customers.cust_id = Orders.cust_id;
(2)
SELECT cust_name, order_num
FROM Customers
INNER JOIN Orders ON Customers.cust_id = Orders.cust_id;
38
我们来让上一题变得更有用些。除了返回顾客名称和订单号,添加第三列 OrderTotal,其中包含每个订单的总价。有两种方法可以执行此操作:使用 OrderItems 表的子查询来创建 OrderTotal 列,或者将 OrderItems 表与现有表联结并使用聚合函数。提示:请注意需要使用完全限定列名的地方。
(1)
SELECT cust_name, order_num, (SELECT sum(quantity * item_price)
FROM OrderItems
WHERE OrderItems.order_num = Orders.order_num) AS OrderTotal
FROM Customers, Orders
WHERE Customers.cust_id = Orders.cust_id;
(2)
SELECT cust_name, Orders.order_num, sum(quantity * item_price) AS OrderTotal
FROM Customers, Orders, OrderItems
WHERE Customers.cust_id = Orders.cust_id AND Orders.order_num = OrderItems.order_num
GROUP BY cust_name, Orders.order_num;
39
我们重新看一下第 33 道挑战题编写 SQL 语句,检索订购产品BR01 的日期,这一次使用联结和简单的等联结语法。输出应该与第11 课的输出相同。
SELECT cust_id, order_date
FROM Orders, OrderItems
WHERE Orders.order_num = OrderItems.order_num AND prod_id = 'BR01';
40
很有趣,我们再试一次。重新创建为第 34 道挑战题 编写的 SQL 语句,这次使用 ANSI 的 INNER JOIN 语法。在之前编写的代码中使用了两个嵌套的子查询。要重新创建它,需要两个 INNER JOIN 语句,每个语句的格式类似于本课讲到的 INNER JOIN 示例,而且不要忘记WHERE 子句可以通过 prod_id 进行过滤。
SELECT cust_id, order_date, cust_email
FROM Orders
INNER JOIN OrderItems ON Orders.order_num = OrderItems.order_num
INNER JOIN Customers ON Orders.cust_id = Customers.cust_id
WHERE prod_id = 'BR01';
41
再让事情变得更加有趣些,我们将混合使用联结、聚合函数和分组。准备好了吗?回到第 10 课,当时的挑战是要求查找值等于或大于 1000的所有订单号。这些结果很有用,但更有用的是订单数量至少达到这个数的顾客名称。因此,编写 SQL 语句,使用联结从 Customers表返回顾客名称(cust_name),并从 OrderItems 表返回所有订单的总价。 提示:要联结这些表,还需要包括 Orders 表(因为 Customers 表与 OrderItems 表不直接相关,Customers 表与 Orders 表相关,而Orders 表与 OrderItems 表相关)。不要忘记 GROUP BY 和 HAVING,并按顾客名称对结果进行排序。你可以使用简单的等联结或 ANSI 的INNER JOIN 语法。或者,如果你很勇敢,请尝试使用两种方式编写。
(1)
SELECT cust_name, sum(quantity * item_price)
FROM Customers, OrderItems, Orders
WHERE Customers.cust_id = Orders.cust_id
AND OrderItems.order_num = Orders.order_num
GROUP BY cust_name
HAVING sum(quantity * item_price) >=1000;
(2)
SELECT cust_name, sum(quantity * item_price)
FROM Orders
INNER JOIN OrderItems ON Orders.order_num = OrderItems.order_num
INNER JOIN Customers ON Customers.cust_id = Orders.cust_id
GROUP BY cust_name
HAVING sum(quantity * item_price) >=1000;
42
使用 INNER JOIN 编写 SQL语句,以检索每个顾客的名称(Customers表中的 cust_name)和所有的订单号(Orders 表中的 order_num)。
SELECT cust_name, order_num
FROM Customers
INNER JOIN Orders ON Orders.cust_id = Customers.cust_id;
43
修改刚刚创建的 SQL 语句,仅列出所有顾客,即使他们没有下过订单。
SELECT cust_name, order_num
FROM Customers
LEFT OUTER JOIN Orders ON Orders.cust_id = Customers.cust_id;
44
使用 OUTER JOIN 联结 Products 表和 OrderItems 表,返回产品名称(prod_name)和与之相关的订单号(order_num)的列表,并按商品名称排序。
SELECT prod_name, order_num
FROM Products
LEFT OUTER JOIN OrderItems ON Products.prod_id = OrderItems.prod_id;
45
修改上一题中创建的 SQL 语句,使其返回每一项产品的总订单数(不是订单号)。
SELECT prod_name, count(order_num)
FROM products
LEFT OUTER JOIN OrderItems ON Products.prod_id = OrderItems.prod_id
GROUP BY prod_name;
46
编写 SQL语句,列出供应商(Vendors 表中的 vend_id)及其可供产品的数量,包括没有产品的供应商。你需要使用 OUTER JOIN 和 COUNT()聚合函数来计算 Products 表中每种产品的数量。注意:vend_id 列会显示在多个表中,因此在每次引用它时都需要完全限定它。
SELECT Vendors.vend_id, count(prod_id)
FROM Vendors
LEFT OUTER JOIN Products ON Vendors.vend_id = Products. vend_id
GROUP BY Vendors.vend_id;
47
编写 SQL 语句,将两个 SELECT 语句结合起来,以便从 OrderItems表中检索产品 ID(prod_id)和 quantity。其中,一个 SELECT 语句过滤数量为 100 的行,另一个 SELECT 语句过滤 ID 以 BNBG 开头的产品。按产品 ID 对结果进行排序。
SELECT quantity, prod_id
FROM OrderItems
WHERE quantity = 100
INTERSECT
SELECT quantity, prod_id
FROM OrderItems
WHERE prod_id LIKE 'BNBG%';
48
重写刚刚创建的 SQL 语句,仅使用单个 SELECT 语句。
SELECT quantity, prod_id
FROM OrderItems
WHERE quantity = 100 AND prod_id LIKE 'BNBG%';
49
编写 SQL 语句,组合 Products 表中的产品名称(prod_name)和 Customers 表中的顾客名称(cust_name)并返回,然后按产品名称对结果进行排序。
SELECT prod_name
FROM Products
UNION
SELECT cust_name
WHERE Customers
ORDER BY prod_name;
50
下面的 SQL 语句有问题吗?(尝试在不运行的情况下指出。)
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state = 'MI'
ORDER BY cust_name;
UNION
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state = 'IL'ORDER BY cust_name;
第一个SELECT
语句最后面不应该加ORDER BY
语句,ORDER BY
语句用改放在最后面且只能写一个。
51
美国各州的缩写应始终用大写。编写 SQL语句来更新所有美国地址,包括供应商状态(Vendors 表中的 vend_state)和顾客状态(Customers表中的 cust_state),使它们均为大写。
UPDATE Vandors
SET vend_state = UPPER(vend_state)
WHERE vend_state = 'USA';
UPDATE Customers
SET cust_state
WHERE cust_state = 'USA';
52
创建一个名为 CustomersWithOrders 的视图,其中包含 Customers表中的所有列,但仅仅是那些已下订单的列。提示:可以在 Orders表上使用 JOIN 来仅仅过滤所需的顾客,然后使用 SELECT 来确保拥有正确的数据。
CREATE VIEW CustomersWithOrders AS
SELECT *
FROM Customers
INNER JOIN Orders ON Orders.cust_id = Customers.cust_id;
53
下面的 SQL 语句有问题吗?(尝试在不运行的情况下指出。)
CREATE VIEW OrderItemsExpanded AS
SELECT order_num,
prod_id,
quantity,
item_price,
quantity*item_price AS expanded_price
FROM OrderItems
ORDER BY order_num;
视图中不允许出现ORDER BY
语句。