程序设计习题 第 10 章 找关联
10.1 主键
1.有销售数据如下:
ID |
Name |
Sales |
010010001 |
Tom |
7,588,420 |
010010002 |
John |
8,953,172 |
010010003 |
Joan |
6,276,185 |
020010004 |
Rocky |
1,281,280 |
020010005 |
Ham |
2,686,043 |
020010006 |
Kate |
5,851,210 |
020010007 |
Rose |
292,254 |
030020008 |
Nomy |
8,216,267 |
030020009 |
Neil |
5,143,192 |
(1)将ID设为主键
(2)查询第2条记录的主键值
(3)为主键建立索引
(4)查找主键值为10010002,20010004,30020008的记录
(5)删除主键
(6)将ID和Name设为主键
(7)查找主键值20010005,"Ham"的记录
10.2 外键
1. 有表格Person和Address如下
表Age
personId |
lastName |
firstName |
1 |
Wang |
Allen |
2 |
Alice |
Bob |
personId 是该表的主键
该表包含一些人的 ID 和他们的姓和名的信息。
表Address
addressId |
personId |
city |
state |
1 |
2 |
New York |
New York |
2 |
3 |
Los Angeles |
California |
addressId 是该表的主键
该表的每一行都包含一个 ID = PersonId 的人的城市和州的信息
(1)使用 switch函数, 以Address为事实表,将外键字段转成对应的维表记录,对应记录不存在时置为 null。
(2)将维表记录中的lastName添加到表Address中,效果如下
2. 有某产品的Customers表和Orders表,找出购买过产品的客户名单(用switch和join两种方法实现)
表Customers
id |
name |
1 |
Joe |
2 |
Henry |
3 |
Sam |
4 |
Max |
表Orders
id |
customerId |
amount |
1 |
3 |
787 |
2 |
1 |
675 |
3 |
3 |
203 |
3. 在第2题的Customers和Orders表格中找出未购买过产品的客户名单
4. 有员工薪资表和部门表如下,求各部门工资最高的员工及其工资
Employee
id |
name |
salary |
departmentId |
1 |
Joe |
70000 |
1 |
2 |
Henry |
90000 |
1 |
3 |
Sam |
80000 |
2 |
4 |
Max |
60000 |
2 |
5 |
Jim |
90000 |
1 |
Department
id |
name |
1 |
IT |
2 |
Sales |
注意,工资最高的员工可能不止一个
5. 有客户订单表和订单明细表如下,
Orders
OrderID |
Customer |
Area |
Orderdate |
1001 |
Tom |
west |
2020/2/5 |
1002 |
Jack |
south |
2020/2/5 |
1003 |
Tim |
east |
2020/2/5 |
1004 |
Rose |
north |
2020/2/6 |
1005 |
Kate |
east |
2020/2/6 |
1006 |
John |
south |
2020/2/7 |
1007 |
Horn |
north |
2020/2/7 |
Order_detail
OrderID |
Index |
Product |
Price |
Quantity |
1001 |
1 |
p1 |
12.5 |
32 |
1001 |
2 |
p2 |
14.3 |
55 |
1001 |
3 |
p3 |
15.7 |
14 |
1002 |
1 |
p1 |
12.5 |
10 |
1002 |
2 |
p3 |
15.7 |
8 |
1003 |
1 |
p1 |
12.5 |
36 |
1003 |
2 |
p4 |
8.8 |
15 |
1003 |
3 |
p6 |
62.3 |
85 |
1004 |
1 |
p2 |
14.3 |
24 |
1005 |
1 |
p3 |
15.7 |
12 |
1005 |
2 |
p4 |
8.8 |
27 |
1006 |
1 |
p1 |
12.5 |
18 |
1006 |
2 |
p4 |
8.8 |
92 |
1006 |
3 |
p6 |
62.3 |
10 |
1007 |
1 |
p3 |
15.7 |
6 |
1007 |
2 |
p5 |
24.8 |
8 |
(1)请查出订单总金额大于 1000 的客户订单信息。
提示:一份订单包含多种产品,订单总金额等于订单内所有产品金额的总和。
结果示例:
(2)查出 north 地区的客户订单明细信息。
结果示例:
6. 有运费标准表和运输订单表如下
Freight
City |
First1KG |
Add1KG |
Alabama |
12 |
3 |
Alaska |
11 |
5 |
Arizona |
11 |
5 |
Arkansas |
10 |
5 |
Boston |
12 |
3 |
California |
10 |
4 |
Colorado |
10 |
4 |
Connecticut |
12 |
5 |
Orders
OID |
City |
WeightKG |
100001 |
Arizona |
15 |
100002 |
Arkansas |
13 |
100003 |
Boston |
11 |
100004 |
Colorado |
3 |
100005 |
Connecticut |
2.5 |
100006 |
Arizona |
8 |
100007 |
Alabama |
3.6 |
100008 |
Alaska |
22 |
100009 |
California |
19 |
根据运费标准表,求实际运费。
提示:实际运费 = 首重运费 + 超出重量 * 超重单价,其中不满 1KG 的按 1Kg 计算
7. 有员工就餐数据和餐费标准如下
Meal
Name |
Mealtype |
Tom |
breakfast |
John |
lunch |
Joan |
supper |
Rocky |
breakfast |
Ham |
lunch |
Kate |
supper |
Rose |
breakfast |
Nomy |
lunch |
Neil |
supper |
Jack |
breakfast |
Joe |
lunch |
Peter |
supper |
Sunny |
breakfast |
Tiger |
lunch |
Alice |
breakfast |
Cindy |
lunch |
Leon |
supper |
Lily |
breakfast |
Kevin |
lunch |
Shelly |
supper |
Panzy |
breakfast |
Maggie |
lunch |
Mark |
supper |
Aileen |
breakfast |
Charge
Mealtype |
Mealcharge |
breakfast |
10 |
lunch |
15 |
supper |
20 |
计算Meal表格中每个员工的餐费
8. 区间关联
有数量表和价格标准表,计算数量表中对应的价格
Quantity
Quantity |
221 |
87 |
33 |
73 |
162 |
227 |
403 |
288 |
78 |
213 |
374 |
152 |
Price
StartQuantity |
EndQuantity |
Price |
0 |
50 |
15 |
50 |
100 |
13.75 |
100 |
300 |
13 |
300 |
500 |
12.5 |
提示:segp()为pseg()的选出函数,根据区段号返回对应的成员
结果示例:
10.3 归并
1. 有 2018、2019 年的销售订单表数据如下,两个 Sheet 有相同的列结构:
2018
OrderID |
CustomerID |
ProductID |
OrderDate |
Amount |
10248 |
VINET |
11 |
2018-07-04 |
168 |
10248 |
VINET |
42 |
2018-07-04 |
98 |
10248 |
VINET |
72 |
2018-07-04 |
174 |
10249 |
TOMSP |
14 |
2018-07-05 |
167.4 |
10249 |
TOMSP |
51 |
2018-07-05 |
1696 |
10250 |
HANAR |
41 |
2018-07-08 |
77 |
10250 |
HANAR |
51 |
2018-07-08 |
1484 |
10250 |
HANAR |
65 |
2018-07-08 |
252 |
10251 |
VICTE |
22 |
2018-07-08 |
100.8 |
10251 |
VICTE |
57 |
2018-07-08 |
234 |
10251 |
VICTE |
65 |
2018-07-08 |
336 |
10252 |
SUPRD |
20 |
2018-07-09 |
2592 |
10252 |
SUPRD |
33 |
2018-07-09 |
50 |
10252 |
SUPRD |
60 |
2018-07-09 |
1088 |
10253 |
HANAR |
31 |
2018-07-10 |
200 |
2019
OrderID |
CustomerID |
ProductID |
OrderDate |
Amount |
10400 |
EASTC |
29 |
2019-01-01 |
2079 |
10400 |
EASTC |
35 |
2019-01-01 |
504 |
10400 |
EASTC |
49 |
2019-01-01 |
480 |
10401 |
RATTC |
30 |
2019-01-01 |
372.6 |
10401 |
RATTC |
56 |
2019-01-01 |
2128 |
10401 |
RATTC |
65 |
2019-01-01 |
336 |
10401 |
RATTC |
71 |
2019-01-01 |
1032 |
10402 |
ERNSH |
23 |
2019-01-02 |
432 |
10402 |
VINET |
72 |
2019-01-02 |
2281.5 |
10403 |
ERNSH |
16 |
2019-01-03 |
291.9 |
10403 |
ERNSH |
48 |
2019-01-03 |
714 |
10404 |
HANAR |
65 |
2019-01-03 |
747 |
10404 |
MAGAA |
42 |
2019-01-03 |
448 |
10404 |
MAGAA |
49 |
2019-01-03 |
480 |
10405 |
LINOD |
3 |
2019-01-06 |
400 |
(1)找出这两年同一客户(CustomerID)购买同一产品(ProductID)的订单
(2)将两年的订单合并到一张表,并统计每个客户的总金额
(3)找出 2019 年新增客户的订单情况:
(4)找出 2019 年所有流失的客户名单 CustomerID
2. 有一月份和二月份销售额排名前十的产品名称和销售员姓名
Jan
ProductName |
Name |
Sasquatch Ale |
Sunny |
Steeleye Stout |
Mark |
Aniseed Syrup |
Peter |
Chef Anton's Cajun Seasoning |
Sunny |
Chef Anton's Gumbo Mix |
Mark |
Genen Shouyu |
Mark |
Grandma's Boysenberry Spread |
Sunny |
Gula Malacca |
Sunny |
Louisiana Fiery Hot Pepper Sauce |
Peter |
Louisiana Hot Spiced Okra |
Peter |
Feb
ProductName |
Name |
Northwoods Cranberry Sauce |
Mark |
Original Frankfurter grüne So?e |
Peter |
Chef Anton's Cajun Seasoning |
Ben |
Genen Shouyu |
Mark |
Louisiana Fiery Hot Pepper Sauce |
Peter |
Sasquatch Ale |
John |
Valkoinen suklaa |
Mark |
Zaanse koeken |
Peter |
Camembert Pierrot |
Sunny |
Flotemysost |
Mark |
(1)以ProductName为关键列,找出一二月份均进入前十的产品数据(销售员姓名列出一月份的即可)
(2)以ProductName为关键列,找出一、二月份有一次以上进入前十的产品数据
(3)以ProductName为关键列,找出一月份进了前十但是二月份没有进前十的产品销售数据
(4)基于整行数据对比,找出一二月份均进入前十的产品及销售员的数据
3. 多个表格归并
有多个月份的销售数据top10Sales如下,并且随着时间的推移,月数还会增加。
top10Sales.xlsx
求这几个月全部进了前十的产品名单
4. 某商家根据销售渠道不同,销售记录分别存储在线上和实体店两个表。有时线上线下同时搞活动,部分销售记录被同时存储在两个表中。销售表结构相同,如下:
online
OrderID |
Customer |
SellerId |
OrderDate |
Amount |
10400 |
EASTC |
1 |
2014/1/1 |
3063 |
10401 |
HANAR |
1 |
2014/1/1 |
3868.6 |
10402 |
ERNSH |
8 |
2014/1/2 |
2713.5 |
10403 |
ERNSH |
4 |
2014/1/3 |
1005.9 |
10404 |
MAGAA |
2 |
2014/1/3 |
1675 |
store
OrderID |
Customer |
SellerId |
OrderDate |
Amount |
10402 |
ERNSH |
8 |
2014/1/2 |
2713.5 |
10403 |
ERNSH |
4 |
2014/1/3 |
1005.9 |
10405 |
TOMSP |
5 |
2014/1/3 |
2592 |
10406 |
VICTE |
3 |
2014/1/4 |
252 |
10407 |
SUPRD |
2 |
2014/1/5 |
100.8 |
(1)请汇总线上和线下的订单数据,并计算商家实际的总销售额
(2)查找线上线下重复保存的销售记录
5. 根据版本不同的两个交易信息储存文件 old.xlsx 和 new.xlsx,分别找出新增的、删除的和修改的记录。
old.xlsx:
UserName |
Date |
SaleValue |
SaleCount |
Rachel |
2015/3/1 |
4500 |
9 |
Rachel |
2015/3/3 |
8700 |
4 |
Tom |
2015/3/2 |
3000 |
8 |
Tom |
2015/3/3 |
5000 |
7 |
Tom |
2015/3/4 |
6000 |
12 |
John |
2015/3/2 |
4000 |
3 |
John |
2015/3/2 |
4300 |
9 |
John |
2015/3/4 |
4800 |
4 |
new.xlsx
UserName |
Date |
SaleValue |
SaleCount |
Rachel |
2015/3/1 |
4500 |
9 |
Rachel |
2015/3/2 |
5000 |
5 |
Ashley |
2015/3/1 |
6000 |
5 |
Rachel |
2015/3/3 |
11700 |
4 |
Tom |
2015/3/3 |
5000 |
7 |
Tom |
2015/3/4 |
6000 |
12 |
John |
2015/3/2 |
4000 |
3 |
John |
2015/3/2 |
4300 |
9 |
John |
2015/3/4 |
4800 |
4 |
10.4 连接
1. 有某产品的Customers表和Orders表
id |
name |
1 |
Joe |
2 |
Henry |
3 |
Sam |
4 |
Max |
表Orders
id |
customerId |
amount |
1 |
3 |
787 |
2 |
1 |
675 |
3 |
3 |
203 |
(1)找出购买过产品的客户姓名和其消费总额
(2)找出未购买过产品的客户名单
2. 有两张表格,分别为某些肉类产品的价格表和库存表,现需要将两张表格横向连接到一起。
Meats.xlsx
Name |
UnitPrice |
Mutton |
7.69 |
Pork |
4.58 |
Chicken |
5.77 |
Beef |
7.96 |
MeatStock.xlsx
Name |
Stock |
MinimumStock |
Mutton |
5000 |
3000 |
Chicken |
4000 |
3000 |
Duck |
2500 |
2000 |
Beef |
3600 |
2000 |
(1)按照Name进行连接,连接后保留所有行数据
(2)按照Name连接,只保留两个文件中都有的行
(3)按照Name连接,保留第一个文件的行
3. 如下两个表格,按照Region和Name两个字段连接,保留第一个文件的行
MeatsRegion.xlsx
Region |
Name |
UnitPrice |
A |
Mutton |
7.69 |
A |
Pork |
4.58 |
A |
Chicken |
5.77 |
A |
Beef |
7.96 |
B |
Mutton |
6.32 |
B |
Pork |
4.13 |
B |
Chicken |
6.33 |
MeatRegionStock.xlsx
Region |
Name |
Stock |
MinimumStock |
A |
Mutton |
500 |
3000 |
A |
Chicken |
4000 |
3000 |
A |
Duck |
2500 |
2000 |
A |
Beef |
3600 |
2000 |
B |
Mutton |
2000 |
1500 |
B |
Pork |
600 |
300 |
B |
Beef |
3200 |
2000 |
连接后效果:
4. 有两张表格
Types.xlsx
Type |
Description |
Fruits |
Edible plant fruit which is succulent and tastes mainly sweet and sour |
Meats |
Edible subcutaneous tissue and muscle of animals |
Foods.xlsx
Type |
Name |
UnitPrice |
Fruits |
Apple |
1.69 |
Fruits |
Banana |
0.69 |
Fruits |
Peach |
0.88 |
Fruits |
Strawberry |
1.97 |
Meats |
Mutton |
7.69 |
Meats |
Pork |
4.58 |
Meats |
Chicken |
5.77 |
Meats |
Duck |
6.89 |
Meats |
Beef |
7.96 |
按照Type连接,将Description添加到每种 food 的后面
连接后效果:
5. 根据社区人员表和年龄分段表,查询社区居民所处的年龄段。(用xjoin()实现)
Community:
ID |
Name |
Age |
1 |
David |
28 |
2 |
Daniel |
15 |
3 |
Andrew |
65 |
4 |
Rudy |
Age:
Group |
Start |
End |
Children |
0 |
15 |
Youth |
16 |
40 |
Middle |
41 |
60 |
Old |
61 |
100 |
查询效果:
参考答案
10.1 主键
1.
A |
|
1 |
=T("Sales.xlsx") |
2 |
=A1.keys(ID) |
3 |
=A1(2).key() |
4 |
>A1.index() |
5 |
=A1.find(10010002,20010004,30020008) |
6 |
=A1.keys() |
7 |
=A1.keys(ID,Name) |
8 |
=A1.find([20010005,"Ham"]) |
10.2 外键
1.
A |
|
1 |
=T("Person.xlsx").keys(personId) |
2 |
=T("Address.xlsx").keys(addressId) |
3 |
>A2.switch(personId,A1) |
4 |
=A2.new(addressId,personId.lastName:lastName,city,state) |
2.
A |
|
1 |
=T("Customers.xlsx").keys(id) |
2 |
=T("Orders").keys(id) |
3 |
>A2.switch(customerId,A1) |
4 |
=A2.(customerId.name).id() |
A |
|
1 |
=T("Customers.xlsx").keys(id) |
2 |
=T("Orders").keys(id) |
3 |
=A2.join(customerId,A1,name).(name).id() |
3.
A |
|
1 |
=T("Customers.xlsx").keys(id) |
2 |
=T("Orders").keys(id) |
3 |
=A2.group(customerId;) |
4 |
=A1.join@d(id,A3:customerId) |
4.
A |
|
1 |
=T("Employee").keys(id) |
2 |
=T("Department").keys(id) |
3 |
=A1.join(departmentId,A2,name:deptname) |
4 |
=A3.group(deptname;~.maxp@a(salary).(name):name,~.max(salary):salary) |
5.
(1)
A |
|
1 |
=T(“Orders.xlsx”) |
2 |
=T(“Order_detail.xlsx”) |
3 |
=A2.groups(OrderID;sum(Price*Quantity):Amount).select(Amount>1000) |
4 |
=A1.join@i(OrderID,A3:OrderID) |
(2)
A |
|
1 |
=T(“Orders.xlsx”) |
2 |
=T(“Order_detail.xlsx”) |
3 |
=A1.select(Area==“north”) |
4 |
=A2.join@i(OrderID,A3:OrderID) |
6.
A |
|
1 |
=T(“Freight.xlsx”) |
2 |
=T(“Orders.xlsx”) |
3 |
=A2.join(City,A1:City,First1KG+(ceil(WeightKG)-1)*Add1KG:Fee) |
7.
A |
|
1 |
=T(“Meal.xlsx”) |
2 |
=T(“Charge.xlsx”) |
3 |
=A1.join(Mealtype, A2:Mealtype, Mealcharge) |
8.
A |
|
1 |
=T(“Quantity.xlsx”) |
2 |
=T(“Price.xlsx”) |
3 |
=A1.derive(A2.segp@r(StartQuantity,Quantity).Price:Price) |
10.3 归并
1.
(1)
A |
|
1 |
=T(“2018.xlsx”) |
2 |
=T(“2019.xlsx”) |
3 |
=[A1,A2].merge@io(CustomerID,ProductID) |
(2)
A |
|
1 |
=T(“2018.xlsx”) |
2 |
=T(“2019.xlsx”) |
3 |
=[A1,A2].merge@o(OrderID) |
4 |
=A3.groups(CustomerID;sum(Amount):TotalAmount) |
(3)
A |
|
1 |
=T(“2018.xlsx”) |
2 |
=T(“2019.xlsx”) |
3 |
=A2.id(CustomerID)\A1.id(CustomerID) |
4 |
=A2.select(A3.contain(CustomerID)) |
(4)
A |
|
1 |
=T(“2018.xlsx”) |
2 |
=T(“2019.xlsx”) |
3 |
=A1.id(CustomerID)\A2.id(CustomerID) |
2.
A |
|
1 |
=T(“Jan.xlsx”) |
2 |
=T(“Feb.xlsx”) |
3 |
=[A1,A2].merge@oi(ProductName) |
4 |
=[A1,A2].merge@ou(ProductName) |
5 |
=[A1,A2].merge@od(ProductName) |
6 |
=[A1,A2].merge@oi() |
3.
A |
|
1 |
=file("top10Sales.xlsx").xlsopen() |
2 |
=A1.(A1.xlsimport@t(;stname)).merge@oi(ProductName) |
4.
(1)
A |
|
1 |
=T("Online.xlsx") |
2 |
=T("Store.xlsx") |
3 |
=A1.sort(OrderID) |
4 |
=A2.sort(OrderID) |
5 |
=[A3,A4].merge@u(OrderID) |
6 |
=A5.sum(Amount) |
(2)
A |
|
1 |
=T("Online.xlsx") |
2 |
=T("Store.xlsx") |
3 |
=A1.sort(OrderID) |
4 |
=A2.sort(OrderID) |
5 |
=[A3,A4].merge@i(OrderID) |
5.
A |
|
1 |
=T("old.xlsx") |
2 |
=T("new.xlsx") |
3 |
=A1.sort(UserName,Date) |
4 |
=A2.sort(UserName,Date) |
5 |
=new=[A4,A3].merge@d(UserName,Date) |
6 |
=delete=[A3,A4].merge@d(UserName,Date) |
7 |
=diff=[A4,A3].merge@d(UserName,Date,SaleValue,SaleCount) |
8 |
=update=[diff,new].merge@d(UserName,Date) |
9 |
return [new, delete, update] |
10.4 连接
1.
(1)
A |
|
1 |
=T("Customers.xlsx") |
2 |
=T("Orders") |
3 |
=A2.groups(customerId;sum(amount):Amount) |
4 |
=join(A1:a,id;A3:b,customerId) |
5 |
=A4.new(a.name,b.Amount) |
(2)
A |
|
1 |
=T("Customers.xlsx") |
2 |
=T("Orders") |
3 |
=A2.groups(customerId) |
4 |
=join@d(A1:a,id;A3:b,customerId) |
2.
(1)
A |
|
1 |
=file("Meats.xlsx").xlsimport@t() |
2 |
=file("MeatStock.xlsx").xlsimport@t() |
3 |
=join@f(A1:Price,Name;A2:Stock,Name) |
4 |
=A3.new([Price.Name,Stock.Name].ifn():Name,Stock.Stock,Stock.MinimumStock,Price.UnitPrice) |
5 |
=file("MeatsPriceStock.xlsx").xlsexport@t(A4) |
(2)
A |
|
1 |
=file("Meats.xlsx").xlsimport@t() |
2 |
=file("MeatStock.xlsx").xlsimport@t() |
3 |
=join(A1:Price,Name;A2:Stock,Name) |
4 |
=A3.new(Stock.Name,Stock.Stock,Stock.MinimumStock,Price.UnitPrice) |
5 |
=file("MeatsPriceStock.xlsx").xlsexport@t(A4) |
(3)
A |
|
1 |
=file("Meats.xlsx").xlsimport@t() |
2 |
=file("MeatStock.xlsx").xlsimport@t() |
3 |
=join@1(A1:Price,Name;A2:Stock,Name) |
4 |
=A3.new(Price.Name,Stock.Stock,Stock.MinimumStock,Price.UnitPrice) |
5 |
=file("MeatsPriceStock.xlsx").xlsexport@t(A4) |
3.
A |
|
1 |
=file("MeatsRegion.xlsx").xlsimport@t() |
2 |
=file("MeatRegionStock.xlsx").xlsimport@t() |
3 |
=join@1(A1:Price,Region,Name;A2:Stock,Region,Name) |
4 |
=A3.new(Price.Region,Price.Name,Stock.Stock,Stock.MinimumStock,Price.UnitPrice) |
5 |
=file("MeatsPriceStock.xlsx").xlsexport@t(A4) |
4.
A |
|
1 |
=T("Types.xlsx") |
2 |
=T("Foods.xlsx") |
3 |
=join@f(A1:Type,Type;A2:Food,Type) |
4 |
=A3.new(Food.Type,Food.Name,Food.UnitPrice,Type.Description) |
5 |
=T("FoodsDescription.xlsx",A4) |
5.
A |
|
1 |
=T("Community.xlsx") |
2 |
=T("Age.xlsx") |
3 |
=xjoin@1(A1:Person; A2:Age, A2.Start<=Person.Age && A2.End>=Person.Age) |
4 |
=A3.new(Person.ID:ID, Person.Name:Name, Person.Age:Age,Age.Group:Group) |
英文版