微软NorthWind

本文章的练习题来自Microsoft的Northwind项目,是一个开源的数据库练习项目。

经过一个上午的练习,一口气将34道练习题做完了。

对于这个练习题,我的评价是难度不大,很适合上手,另外一个45道题的刷题本可就比这难多了!

数据准备

数据源是从Git上下载的, 微软的北风项目的源数据

Northwind数据库在我的博客园

MySQL刷题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
-- 需求1: 选中employees 表的所有数据
select * from employees;

-- 需求2: 查询每个客户的 ID, company name, contact name, contact title, city, 和 country.并按照国家名字排序
select customer_id,company_name,contact_name,contact_title,city,country from customers;

-- 替换快捷键: ctrl + 字母R
-- 需求3: 查询每一个商品的product_name, category_name, quantity_per_unit, unit_price, units_in_stock 并且通过 unit_price 字段排序
-- 方式1: 显示内连接
select product_name,
category_name,
quantity_per_unit,
unit_price,
units_in_stock
from products inner join categories c on products.category_id = c.category_id;
-- 方式2: 隐式内连接.
select product_name,
category_name,
quantity_per_unit,
unit_price,
units_in_stock
from products,categories where products.category_id=categories.category_id;

-- 需求4: 列出所有提供了4种以上不同商品的供应商列表所需字段:supplier_id, company_name, and products_count (提供的商品种类数量).
select
s.supplier_id,
company_name
from products p inner join suppliers s on p.supplier_id=s.supplier_id
group by s.supplier_id, company_name having count(p.supplier_id)>4;

-- 需求5: 提取订单编号为10250的订单详情, 显示如下信息:
-- product_name, quantity, unit_price ( order_items 表), discount , order_date 按商品名字排序
select
product_name,
quantity,
oi.unit_price,
discount,
order_date
from products p inner join order_items oi on oi.product_id=p.product_id
inner join orders on oi.order_id=orders.order_id where oi.order_id='10250';

-- 需求6: 收集运输到法国的订单的相关信息,包括订单涉及的顾客和员工信息,下单和发货日期等.
select
employee_id,
customer_id,
order_date,
shipped_date
from orders where ship_country='France';

-- 需求7: 提供订单编号为10248的相关信息,包括product name, unit price (在 order_items 表中), quantity(数量),company_name(供应商公司名字 ,起别名 supplier_name).
select
product_name,
p.unit_price,
quantity,
company_name as supplier_name
from products p inner join order_items o on o.product_id = p.product_id
inner join suppliers s on p.supplier_id = s.supplier_id where order_id=10248;

-- 需求8: 提取每件商品的详细信息,包括 商品名称(product_name), 供应商的公司名称 (company_name,在 suppliers 表中),
-- 类别名称 category_name, 商品单价unit_price, 和每单位商品数量quantity per unit
select
product_name,
company_name,
category_name,
unit_price,
quantity_per_unit
from products inner join categories c on products.category_id = c.category_id
inner join suppliers s on products.supplier_id = s.supplier_id;

-- 需求9: 另一种常见的报表需求是查询某段时间内的业务指标, 我们统计2016年7月的订单数量,
select
count(order_id)
from orders where order_date>='2016-07-01' and order_date<'2016-08-01';

-- 需求11: 统计每个供应商供应的商品种类数量, 结果返回供应商IDsupplier_id
-- ,公司名字company_name ,商品种类数量(起别名products_count )使用 products 和 suppliers 表.
select
products.supplier_id,
company_name,
count(product_id) as products_count
from products inner join suppliers s on products.supplier_id = s.supplier_id;

-- 需求12: 我们要查找ID为10250的订单的总价(折扣前),SUM(unit_price * quantity)
select
sum(unit_price * order_items.quantity) as '折扣前总金额',
sum(unit_price * (1-order_items.discount) * order_items.quantity) as '折扣后总金额'
from order_items where order_id=10250;

-- 需求13: 统计每个员工处理的订单总数, 结果包含员工IDemployee_id,姓名first_name 和 last_name,处理的订单总数(别名 orders_count)
select
employees.employee_id,
first_name,
last_name,
count(order_id) as orders_count
from employees inner join orders o on employees.employee_id = o.employee_id group by employee_id, first_name, last_name;

-- 需求14: 统计每个类别中的库存产品值多少钱?显示三列:category_id, category_name, 和 category_total_value, 如何计算库存商品总价:SUM(unit_price * units_in_stock)。
select
products.category_id,
category_name,
sum(unit_price * units_in_stock) as category_total_value
from products inner join categories c on products.category_id = c.category_id
group by category_id, category_name ;

-- 需求15: 计算每个员工的订单数量
select
employee_id,
count(order_id)
from orders group by employee_id;

-- 需求16: 计算每个客户的下订单数 结果包含:用户id、用户公司名称、订单数量(customer_id, company_name, orders_count )
select
customers.customer_id,
company_name,
count(order_id) as orders_count
from customers inner join orders o on customers.customer_id = o.customer_id group by customers.customer_id, company_name;

-- 需求17: 统计2016年6月到2016年7月用户的总下单金额并按金额从高到低排序
-- 结果包含:顾客公司名称company_name 和总下单金额(折后实付金额)total_paid
-- 提示:
-- 计算实际总付款金额: SUM(unit_price quantity (1 - discount))
-- 日期过滤 WHERE order_date >= '2016-06-01' AND order_date < '2016-08-01'
select
company_name,
sum(unit_price * order_items.quantity * (1-discount)) as total_paid
from order_items inner join orders o on order_items.order_id = o.order_id
inner join customers c on o.customer_id = c.customer_id
where order_date>='2016-06-01' and order_date<'2016-08-01' group by c.customer_id,company_name;

-- 需求18: 统计客户总数和带有传真号码的客户数量
-- 需要字段:all_customers_count 和 customers_with_fax_count
select
count(*) as all_customers_count,
count(fax) as customers_with_fax_count
from customers;

-- 需求19: 我们要在报表中显示每种产品的库存量,但我们不想简单地将“ units_in_stock”列放在报表中。报表中只需要一个总体级别,例如低,高:
-- 库存大于100 的可用性为高(high)
-- 50到100的可用性为中等(moderate)
-- 小于50的为低(low)
-- 零库存 为 (none)
select
product_name,
case
when units_in_stock>100 then '高'
when units_in_stock>50 and count(units_in_stock)<100 then '中等'
when units_in_stock<50 and count(units_in_stock)>0 then '低'
when units_in_stock=0 then '零库存' end as '库存量'
from products group by product_name;

-- 需求20: 创建一个报表,统计员工的经验水平
-- 显示字段:first_name, last_name, hire_date, 和 experience
-- 经验字段(experience ):
-- 'junior' 2014年1月1日以后雇用的员工
-- 'middle' 在2013年1月1日之后至2014年1月1日之前雇用的员工
-- 'senior' 2013年1月1日或之前雇用的员工
select
first_name,
last_name,
case
when hire_date>'2014-01-01' then 'junior'
when hire_date>'2013-01-01' and hire_date<'2014-01-01' then 'middle'
when hire_date<'2013-01-01' then 'senior' end as experience
from employees;

-- 需求21: 我们的商店要针对北美地区的用户做促销活动:任何运送到北美地区(美国,加拿大) 的包裹免运费。 创建报表,查询订单编号为10720~10730 活动后的运费价格
select
order_id,
customer_id,
ship_country,
case when ship_country='USA' or ship_country ='Canada' then '0' end as ship_no_postage
from orders where order_id>'10720' and order_id<'10730';

-- 需求22: 需求:创建客户基本信息报表, 包含字段:客户id customer_id, 公司名字 company_name
-- 所在国家 country, 使用语言language, 使用语言language 的取值按如下规则
-- Germany, Switzerland, and Austria 语言为德语 'German', UK, Canada, the USA, and Ireland -- 语言为英语 'English', 其他所有国家 'Other'
select
customer_id,
company_name,
country,
case
when country='Germany' or country='Switzerland' or country='Austria' then 'German'
when country='UK' or country='Canada' or country='USA' or country='Ireland' then 'English'
else 'Other' end as 'language'
from customers;

-- 需求23: 需求:创建报表将所有产品划分为素食和非素食两类
-- 报表中包含如下字段:产品名字 product_name, 类别名称 category_name
-- 膳食类型 diet_type:
-- 非素食 'Non-vegetarian' 商品类别字段的值为 'Meat/Poultry' 和 'Seafood'.
-- 素食
select
product_name,
category_name,
case
when category_name='Meat/Poultry' or category_name='Seafood' then 'Non-vegetarian'
else 'vegetarian' end as 'diet_type'
from products inner join categories c on products.category_id = c.category_id;

-- 需求24: 在引入北美地区免运费的促销策略时,我们也想知道运送到北美地区和其它国家地区的订单数量
-- 促销策略, 参见需求21的代码.(考察知识点:在GROUP BY后面跟CASE WHEN
select
case when ship_country='USA' or ship_country='Canada' then 0
else 10 end as shipping_count ,
COUNT(*) AS order_count
from orders
GROUP BY
CASE
WHEN ship_country = 'USA' OR ship_country = 'Canada' THEN 0.0
ELSE 10.0
END;

-- 需求25: 创建报表统计供应商来自那个大洲, 报表中包含两个字段:供应商来自哪个大洲(supplier_continent )和 供应产品种类数量(product_count)
-- 供应商来自哪个大洲(supplier_continent )包含如下取值:
-- 'North America' (供应商来自 'USA' 和 'Canada'.)
-- 'Asia' (供应商来自 'Japan' 和 'Singapore')
-- 'Other' (其它国家) (考察知识点:在GROUP BY后面跟CASE WHEN,只有end结尾 不能用as
select
case
when country='USA' or country='Canada' then 'North America'
when country='Japan' or country='Singapore' then 'Asia'
else 'Other' end as 'supplier_continent',
count(category_id)
from suppliers inner join products p on suppliers.supplier_id = p.supplier_id
group by
case
when country='USA' or country='Canada' then 'North America'
when country='Japan' or country='Singapore' then 'Asia'
else 'Other' end ;

-- 需求26: 需求:创建一个简单的报表来统计员工的年龄情况
-- 报表中包含如下字段
-- 年龄( age ):生日大于1980年1月1日 'young' ,其余'old'
-- 员工数量 ( employee_count)
select
case
when birth_date>'1980-01-01' then 'young'
else 'old' end as 'age',
count(employee_id)
from employees
group by
case
when birth_date>'1980-01-01' then 'young'
else 'old' end;

-- 需求27: 统计客户的contact_title 字段值为 ’Owner' 的客户数量
-- 查询结果有两个字段:represented_by_owner 和 not_represented_by_owner
select
count(case when contact_title='Owner' then 123 end) as represented_by_owner,
count(case when contact_title!='Owner' then '2' end) as not_represented_by_owner
from customers;

-- 需求28: Washington (WA) 是 Northwind的主要运营地区,统计有多少订单是由华盛顿地区的员工处理的,
-- 多少订单是有其它地区的员工处理的
-- 结果字段: orders_wa_employees 和 orders_not_wa_employees
select
count(case when region='WA' then 123 end) as orders_wa_employees,
count(case when region!='WA' then 123 end) as orders_not_wa_employees
from employees inner join orders o on employees.employee_id = o.employee_id;

-- 需求29: 创建报表,统计不同类别产品的库存量,将库存量分成两类 >30 和 <=30 两档分别统计数量
-- 报表包含三个字段, 类别名称 category_name, 库存充足 high_availability, 库存紧张 low_availability
-- 简化需求: 统计不同类别产品的库存量
select
category_name,
count(case when units_in_stock>30 then 1 end) as high_availability,
count(case when units_in_stock<30 then 1 end) as high_availability
from categories inner join products p on categories.category_id = p.category_id
group by p.category_id,categories.category_name;

-- 需求30: 创建报表统计运输到法国的的订单中,打折和未打折订单的总数量
-- 结果包含两个字段:full_price (原价)和 discounted_price(打折)
-- select ship_country, discount from orders o, order_items oi where ship_country='France' and o.order_id = oi.order_id; -- 184
select
count(case when discount=0 then 123 end) as full_price,
count(case when discount!=0 then 1 end) as discounted_price
from order_items inner join orders o on order_items.order_id = o.order_id where ship_country='France';

-- (知识点:SUM中使用CASE WHEN进行复杂计算
-- 需求31: 输出报表,统计不同供应商供应商品的总库存量,以及高价值商品的库存量(单价超过40定义为高价值)
-- 结果显示四列:
-- 供应商ID supplier_id
-- 供应商公司名 company_name
-- 由该供应商提供的总库存 all_units
-- 由该供应商提供的高价值商品库存 expensive_units
select
s.supplier_id,
company_name,
sum(units_in_stock) as 'all_units',
count(case when unit_price>40 then 123 end) as 'expensive_units'
from suppliers s inner join products p on s.supplier_id = p.supplier_id
group by supplier_id, company_name;
-- 需求32: 创建报表来为每种商品添加价格标签,贵、中等、便宜
-- 结果包含如下字段:product_id, product_name, unit_price, 和 price_level
-- 价格等级price_level的取值说明:
-- 'expensive' 单价高于100的产品
-- 'average' 单价高于40但不超过100的产品
-- 'cheap' 其他产品
select
product_id,
product_name,
unit_price,
case
when unit_price>100 then 'expensive'
when unit_price>40 and unit_price<100 then 'average'
else 'cheep' end as 'price_level'
from products ;

-- 需求33: 制作报表统计所有订单的总价(不计任何折扣)对它们进行分类。
-- 包含以下字段:
-- order_id
-- total_price(折扣前)
-- price_group
-- 字段 price_group 取值说明:
-- 'high' 总价超过2000美元
-- 'average',总价在$ 600到$ 2,000之间,包括两端
-- 'low' 总价低于$ 600
select
order_id,
sum(unit_price*quantity) as 'total_price',
case
when sum(unit_price*quantity)>2000 then 'high'
when sum(unit_price*quantity)<2000 and sum(unit_price*quantity)>600 then 'average'
when sum(unit_price*quantity)<600 then 'low' end as 'price_group'
from order_items
group by order_id;
-- 需求34: 统计所有订单的运费,将运费高低分为三档
-- 报表中包含三个字段
-- low_freight freight值小于“ 40.0”的订单数
-- avg_freight freight值大于或等于“ 40.0”但小于“ 80.0”的订单数
-- high_freight freight值大于或等于“ 80.0”的订单数
select
order_id,
case
when freight<40.0 then 'low_freight'
when freight>=40.0 and freight<80.0 then 'avg_freight'
when freight>=80.0 then 'high_freight' end as 'postage'
from orders;