商品分析先回答“卖得怎么样”,再回答“哪些商品经常一起出现”。前者看销售额、销量和毛利,后者看购物篮中的共现关系。
SELECT
category,
COUNT(DISTINCT order_id) AS orders,
SUM(quantity) AS units,
ROUND(SUM(revenue), 2) AS revenue,
ROUND(SUM(gross_profit), 2) AS gross_profit,
ROUND(
SUM(gross_profit) / SUM(revenue),
4
) AS gross_margin
FROM v_sales_detail
GROUP BY category
ORDER BY revenue DESC;数码销售额最高,饮水毛利率最高。两个结论并不冲突:销售额描述规模,毛利率描述每元销售额留下多少毛利。
把品类放进“规模 × 效率”矩阵会更容易决定下一步:
高、低的分界可以用中位数、预算目标或历史基线。本项目先不强行贴标签,避免用很小的数据集做过度决策;我们先掌握方法,再结合业务目标设阈值。
SELECT
product_name,
category,
COUNT(DISTINCT order_id) AS orders,
SUM(quantity) AS units,
ROUND(SUM(revenue), 2) AS revenue,
ROUND(SUM(gross_profit), 2) AS gross_profit
FROM v_sales_detail
GROUP BY product_id, product_name, category
ORDER BY revenue DESC;把 product_id 放进分组,是为了避免未来出现同名商品时被合并。展示时可以不显示编号,但计算时要使用稳定键。
商品排名还要同时看订单数与销量。某商品销售额高,可能因为单价高而不是买家多;销量高也可能来自一笔批量订单。orders、units、revenue 和 gross_profit 放在同一行,正是为了把这些可能性分开。
购物篮分析只关心某件商品是否出现在订单中。同一订单里买两件相同商品,仍然只算一次出现,所以先去重:
WITH baskets AS (
SELECT DISTINCT
order_id,
product_id,
product_name
FROM v_sales_detail
)
SELECT *
FROM baskets
ORDER BY order_id, product_id
LIMIT 20;然后让购物篮表和自己连接,找同一订单里的两件不同商品:
WITH baskets AS (
SELECT DISTINCT order_id, product_id, product_name
FROM v_sales_detail
)
SELECT
a.product_name AS product_a,
b.product_name AS product_b,
COUNT(*) AS pair_orders
FROM baskets AS a
JOIN baskets AS b
ON a.order_id = b
条件 a.product_id < b.product_id 同时避免“商品和自己配对”以及“A+B、B+A”重复计数。
为什么第一步必须 DISTINCT?假设订单 O001 中咖啡壶买了 2 件、收纳盒买了 3 件。若直接连接明细,两种商品可能形成多行组合,COUNT(*) 会把一个购物篮膨胀成多次共现;去重后,每件商品在一个订单中只有一次存在记录,共现次数才表示“多少笔订单同时包含它们”。
支持度表示组合占全部订单的比例;置信度表示买了 A 的订单中有多少也买了 B;提升度把这条置信度与 B 的自然出现概率比较。
WITH baskets AS (
SELECT DISTINCT order_id, product_id, product_name
FROM v_sales_detail
), pairs AS (
SELECT
a.product_id AS product_a_id,
a.product_name AS product_a,
b.product_id AS product_b_id,
b.product_name AS product_b,
COUNT(*) AS pair_orders
FROM baskets
例如“手冲咖啡壶 + 收纳盒”共同出现在 85 笔订单中,支持度约 0.167,提升度约 4.072。提升度大于 1 表示两件商品一起出现的程度高于随机预期,但这仍然是关联,不是因果。
用 100 笔订单做一次手算:40 笔含 A,20 笔含 B,12 笔同时含 A 和 B。
这表示购买 A 的订单出现 B 的概率,是 B 在全部订单中自然出现概率的 1.5 倍。置信度有方向:A → B 的分母是 40,而 B → A 的分母是 20,所以后者是 60%;提升度在二元共现中数值相同,但推荐入口和可触达人数不同。
实际推荐不能只按提升度排序。支持度太低的组合可能只是偶然。上面的完整查询已经在 pairs 中用 HAVING COUNT(*) >= 30 限制共同订单数,并在最终结果中只保留提升度大于 1.20 的组合。
阈值应随订单规模调整。订单量扩大后,可以提高最低共同订单数;如果组合太少,则先检查商品类别与分析时间范围。
在把组合放进推荐位之前,再做三层检查:
可以用下面的查询查看组合在不同月份是否稳定:
WITH baskets AS (
SELECT DISTINCT order_id, order_month, product_id
FROM v_sales_detail
), monthly_pairs AS (
SELECT
a.order_month,
a.product_id AS product_a_id,
b.product_id AS product_b_id,
COUNT(*) AS pair_orders
FROM baskets AS a
JOIN baskets AS b
这张月度表不直接证明推荐有效,只用于判断关联是否持续。真正上线组合推荐后,还要通过对照实验比较转化率、连带率和组合毛利。下一节转向客户,把购买日期、频次和金额整合成可维护的客户分群。