DEMO-A100 庫存偏高
現有庫存 90,約為期間淨需求的 3.2 倍。建議先檢查採購節奏與安全庫存設定。
SQL / Python / Reconciliation
這個 Demo 不只是顯示表格:它以唯讀 SQL 合併銷售、退貨與庫存,先驗證報表總額,再標出庫存偏高或期間無需求的品項。所有資料皆為虛構。
DECISION OUTPUT
把報表從「數字列表」轉成能被採購、庫存或營運人員討論的例外清單。
現有庫存 90,約為期間淨需求的 3.2 倍。建議先檢查採購節奏與安全庫存設定。
仍有 40 件庫存,但分析期間沒有淨銷售。建議確認停產、替代品或促銷處理。
NET SALES BY PRODUCT
銷售金額提供排序依據;顏色則指出需要檢視或期間沒有需求的品項。
TRACEABLE RESULT
可依例外狀態或關鍵字縮小資料,並展開查看實際使用的唯讀 SQL。
| 商品代碼 | 名稱 | 分類 | 淨數量 | 淨銷售 | 退貨 | 現有庫存 | 訊號 |
|---|---|---|---|---|---|---|---|
| DEMO-A100 | Atlas Valve | Fixtures | 28 | $33,600 | 0 | 90 | 建議檢視 |
| DEMO-B200 | Beacon Mixer | Fixtures | 9 | $14,400 | 0 | 18 | 持續觀察 |
| DEMO-C300 | Cobalt Panel | Accessories | 11 | $3,850 | 2 | 12 | 持續觀察 |
| DEMO-D400 | Drift Kit | Accessories | 0 | $0 | 0 | 40 | 期間無需求 |
WITH line_net AS (
SELECT
o.order_date,
substr(o.order_date, 1, 7) AS sale_month,
o.order_id,
o.customer_id,
l.product_id,
CASE WHEN l.transaction_type = 'RETURN' THEN -l.quantity ELSE l.quantity END AS net_quantity,
CASE WHEN l.transaction_type = 'RETURN' THEN -l.quantity * l.unit_price ELSE l.quantity * l.unit_price END AS net_amount,
CASE WHEN l.transaction_type = 'RETURN' THEN l.quantity ELSE 0 END AS returned_quantity
FROM sales_orders AS o
INNER JOIN sales_lines AS l ON l.order_id = o.order_id
),
product_summary AS (
SELECT
product_id,
SUM(net_quantity) AS net_quantity,
ROUND(SUM(net_amount), 2) AS net_amount,
SUM(returned_quantity) AS returned_quantity,
COUNT(DISTINCT CASE WHEN net_quantity > 0 THEN order_id END) AS sales_orders,
COUNT(DISTINCT sale_month) AS active_months
FROM line_net
GROUP BY product_id
),
inventory_latest AS (
SELECT product_id, on_hand_quantity
FROM inventory_snapshots
WHERE snapshot_date = (SELECT MAX(snapshot_date) FROM inventory_snapshots)
),
monthly_rank AS (
SELECT
sale_month,
product_id,
SUM(net_amount) AS month_amount,
ROW_NUMBER() OVER (PARTITION BY sale_month ORDER BY SUM(net_amount) DESC, product_id) AS revenue_rank
FROM line_net
GROUP BY sale_month, product_id
)
SELECT
p.product_code,
p.product_name,
p.category,
COALESCE(s.net_quantity, 0) AS net_quantity,
COALESCE(s.net_amount, 0) AS net_amount,
COALESCE(s.returned_quantity, 0) AS returned_quantity,
COALESCE(s.sales_orders, 0) AS sales_orders,
COALESCE(s.active_months, 0) AS active_months,
COALESCE(i.on_hand_quantity, 0) AS on_hand_quantity,
CASE
WHEN COALESCE(s.net_quantity, 0) = 0 THEN 'No demand in period'
WHEN COALESCE(i.on_hand_quantity, 0) >= COALESCE(s.net_quantity, 0) * 3 THEN 'Review inventory level'
ELSE 'Monitor'
END AS inventory_signal,
(
SELECT GROUP_CONCAT(m.sale_month || ' #' || m.revenue_rank, ', ')
FROM monthly_rank AS m
WHERE m.product_id = p.product_id AND m.revenue_rank <= 2
) AS top_months
FROM products AS p
LEFT JOIN product_summary AS s ON s.product_id = p.product_id
LEFT JOIN inventory_latest AS i ON i.product_id = p.product_id
ORDER BY net_amount DESC, p.product_code;