华为大数据面试SQL-供应链库存周转天数计算
一、题目
已知有三张表:
- t1_product_info:产品信息表(product_id, product_name, category)
- t1_daily_inventory:每日库存快照表(product_id, snapshot_date, inventory_qty)
- t1_daily_sales:每日销售明细表(product_id, sale_date, sale_qty)
库存周转天数 = 统计周期内的平均库存量 / 日均销售量。请计算2024年6月每个产品的库存周转天数,结果保留两位小数,按周转天数升序排列。
其中:
- 平均库存量 = 每日库存量之和 / 统计天数
- 日均销售量 = 总销售量 / 统计天数
样例数据
t1_product_info:
+------------+---------------+------------+
| product_id | product_name | category |
+------------+---------------+------------+
| P001 | 交换机A型 | 网络设备 |
| P002 | 服务器B型 | 计算设备 |
| P003 | 光模块C型 | 光传输 |
+------------+---------------+------------+
t1_daily_inventory:
+------------+---------------+---------------+
| product_id | snapshot_date | inventory_qty |
+------------+---------------+---------------+
| P001 | 2024-06-01 | 500 |
| P001 | 2024-06-02 | 480 |
| P001 | 2024-06-03 | 450 |
| P002 | 2024-06-01 | 1200 |
| P002 | 2024-06-02 | 1150 |
| P002 | 2024-06-03 | 1100 |
| P003 | 2024-06-01 | 800 |
| P003 | 2024-06-02 | 780 |
| P003 | 2024-06-03 | 760 |
+------------+---------------+---------------+
t1_daily_sales:
+------------+------------+----------+
| product_id | sale_date | sale_qty |
+------------+------------+----------+
| P001 | 2024-06-01 | 30 |
| P001 | 2024-06-02 | 25 |
| P001 | 2024-06-03 | 35 |
| P002 | 2024-06-01 | 60 |
| P002 | 2024-06-02 | 55 |
| P002 | 2024-06-03 | 65 |
| P003 | 2024-06-01 | 20 |
| P003 | 2024-06-02 | 25 |
| P003 | 2024-06-03 | 15 |
+------------+------------+----------+
三、思路分析
本题是供应链管理中的经典KPI计算,公式清晰但需要注意数据对齐:
-
分别聚合库存和销售:先按product_id分别统计6月份的总库存量(或日均库存量)和总销售量(或日均销售量)。使用SUM和COUNT可以获得计算所需的分子分母。
-
注意数据完整性:如果某个产品在6月份某天没有库存快照或没有销售记录,COUNT的天数会不同。需要统一用30天(6月天数)还是用实际有数据的天数作为分母——本题使用实际有数据的快照天数。
-
计算公式:
周转天数 = (sum(inventory_qty)/count(distinct snapshot_date)) / (sum(sale_qty)/count(distinct sale_date))=avg_daily_inventory / avg_daily_sales。
库存周转天数是华为供应链管理中的核心指标,天数越短说明产品周转越快、资金占用越少、运营效率越高。
| 维度 | 评分 |
|---|---|
| 题目难度 | ⭐️⭐️⭐️ |
| 题目清晰度 | ⭐️⭐️⭐️⭐️⭐️ |
| 业务常见度 | ⭐️⭐️⭐️⭐️⭐️ |
四、逐步推导
1.分别计算每个产品的日均库存和日均销量
对库存表和销售表分别按product_id聚合,计算总和及天数,然后得到日均值。
执行SQL
select
inv.product_id,
sum(inv.inventory_qty) as total_inventory,
count(distinct inv.snapshot_date) as inv_days,
round(sum(inv.inventory_qty) * 1.0 / count(distinct inv.snapshot_date), 2) as avg_inventory
from t1_daily_inventory inv
where inv.snapshot_date >= '2024-06-01' and inv.snapshot_date <= '2024-06-30'
group by inv.product_id
执行结果
+------------+-----------------+----------+---------------+
| product_id | total_inventory | inv_days | avg_inventory |
+------------+-----------------+----------+---------------+
| P001 | 1430 | 3 | 476.67 |
| P002 | 3450 | 3 | 1150.00 |
| P003 | 2340 | 3 | 780.00 |
+------------+-----------------+----------+---------------+
2.计算日均销量
执行SQL
select
product_id,
sum(sale_qty) as total_sales,
count(distinct sale_date) as sale_days,
round(sum(sale_qty) * 1.0 / count(distinct sale_date), 2) as avg_daily_sales
from t1_daily_sales
where sale_date >= '2024-06-01' and sale_date <= '2024-06-30'
group by product_id
执行结果
+------------+-------------+-----------+------------------+
| product_id | total_sales | sale_days | avg_daily_sales |
+------------+-------------+-----------+------------------+
| P001 | 90 | 3 | 30.00 |
| P002 | 180 | 3 | 60.00 |
| P003 | 60 | 3 | 20.00 |
+------------+-------------+-----------+------------------+
3.关联产品信息,计算库存周转天数
将库存和销售的结果与产品信息表关联,计算周转天数 = 日均库存 / 日均销量。
执行SQL
with avg_inv as (
select
product_id,
round(sum(inventory_qty) * 1.0 / count(distinct snapshot_date), 2) as avg_daily_inventory
from t1_daily_inventory
where snapshot_date >= '2024-06-01' and snapshot_date <= '2024-06-30'
group by product_id
),
avg_sale as (
select
product_id,
round(sum(sale_qty) * 1.0 / count(distinct sale_date), 2) as avg_daily_sales
from t1_daily_sales
where sale_date >= '2024-06-01' and sale_date <= '2024-06-30'
group by product_id
)
select
p.product_id,
p.product_name,
p.category,
coalesce(i.avg_daily_inventory, 0) as avg_daily_inventory,
coalesce(s.avg_daily_sales, 0) as avg_daily_sales,
case
when coalesce(s.avg_daily_sales, 0) = 0 then null
else round(i.avg_daily_inventory / s.avg_daily_sales, 2)
end as turnover_days
from t1_product_info p
left join avg_inv i on p.product_id = i.product_id
left join avg_sale s on p.product_id = s.product_id
order by turnover_days
执行结果
+------------+---------------+------------+---------------------+------------------+----------------+
| product_id | product_name | category | avg_daily_inventory | avg_daily_sales | turnover_days |
+------------+---------------+------------+---------------------+------------------+----------------+
| P003 | 光模块C型 | 光传输 | 780.00 | 20.00 | 39.00 |
| P001 | 交换机A型 | 网络设备 | 476.67 | 30.00 | 15.89 |
| P002 | 服务器B型 | 计算设备 | 1150.00 | 60.00 | 19.17 |
+------------+---------------+------------+---------------------+------------------+----------------+
分析:交换机A型(P001)周转天数最短(15.89天),说明该产品动销最快、库存效率最高;光模块C型(P003)周转天数最长(39天),可能需要关注库存积压风险。
五、常见坑点
坑1:NULL值的隐式处理 — 聚合函数跳过NULL,窗口函数不跳过。WHERE需显式过滤或用COALESCE替代。
坑2:数据类型不一致导致JOIN失效 — string vs int隐式转换可能触发全表扫描,性能骤降。
六、举一反三
-
增加时间维度对比:按天/周/月分组,观察指标的趋势和季节性波动
-
增加分组维度:按品类/地区/渠道拆解,发现差异化的业务洞察
-
设置预警阈值:在WHERE中加阈值判断,自动筛选异常数据
七、知识点总结
| 考点 | 说明 |
|---|---|
| 多表JOIN | LEFT JOIN保留主表所有数据,COALESCE处理NULL |
| GROUP BY + 聚合函数 | 分组聚合是数据分析的基础,配合HAVING筛选分组结果 |
| 日期函数 | DATEDIFF / DATE_ADD / unix_timestamp处理日期运算 |
| NULL值处理 | NULL在聚合和窗口函数中的差异,COALESCE/NVL的替代方案 |
八、建表语句和数据插入
点击展开 DDL & DML
--建表语句
CREATE TABLE IF NOT EXISTS t1_product_info (
product_id STRING COMMENT '产品ID',
product_name STRING COMMENT '产品名称',
category STRING COMMENT '产品类别'
);
CREATE TABLE IF NOT EXISTS t1_daily_inventory (
product_id STRING COMMENT '产品ID',
snapshot_date STRING COMMENT '库存快照日期',
inventory_qty BIGINT COMMENT '当日库存量'
);
CREATE TABLE IF NOT EXISTS t1_daily_sales (
product_id STRING COMMENT '产品ID',
sale_date STRING COMMENT '销售日期',
sale_qty BIGINT COMMENT '当日销售量'
);
--数据插入
INSERT INTO t1_product_info(product_id, product_name, category) VALUES
('P001', '交换机A型', '网络设备'),
('P002', '服务器B型', '计算设备'),
('P003', '光模块C型', '光传输');
INSERT INTO t1_daily_inventory(product_id, snapshot_date, inventory_qty) VALUES
('P001', '2024-06-01', 500),
('P001', '2024-06-02', 480),
('P001', '2024-06-03', 450),
('P002', '2024-06-01', 1200),
('P002', '2024-06-02', 1150),
('P002', '2024-06-03', 1100),
('P003', '2024-06-01', 800),
('P003', '2024-06-02', 780),
('P003', '2024-06-03', 760);
INSERT INTO t1_daily_sales(product_id, sale_date, sale_qty) VALUES
('P001', '2024-06-01', 30),
('P001', '2024-06-02', 25),
('P001', '2024-06-03', 35),
('P002', '2024-06-01', 60),
('P002', '2024-06-02', 55),
('P002', '2024-06-03', 65),
('P003', '2024-06-01', 20),
('P003', '2024-06-02', 25),
('P003', '2024-06-03', 15);
「数据仓库技术」文章同步更新,不错过每一篇干货

备注「数据仓库技术」加入社群,每日一道大厂SQL真题
