Как посчитать gross margin по продукту в SQL
Содержание:
Зачем margin по продукту
Average gross margin компании 45% скрывает то, что половина SKU имеет 60%, а другая — 20%. Маржу по продукту считают, чтобы:
- найти убыточные позиции (cost outpaces price)
- сегментировать портфолио
- скорректировать pricing
- prioritize marketing на high-margin
Формула
gross_margin = (revenue − COGS) / revenueCOGS = cost of goods sold — прямая стоимость производства / закупки.
Margin в SQL
SELECT
p.product_id,
p.product_name,
SUM(oi.quantity * oi.unit_price) AS revenue,
SUM(oi.quantity * p.unit_cost) AS cogs,
SUM(oi.quantity * oi.unit_price) - SUM(oi.quantity * p.unit_cost) AS gross_profit,
(SUM(oi.quantity * oi.unit_price) - SUM(oi.quantity * p.unit_cost))::NUMERIC * 100
/ NULLIF(SUM(oi.quantity * oi.unit_price), 0) AS gross_margin_pct
FROM order_items oi
JOIN products p USING (product_id)
WHERE oi.order_date >= CURRENT_DATE - INTERVAL '90 days'
GROUP BY p.product_id, p.product_name
HAVING SUM(oi.quantity) >= 10
ORDER BY gross_margin_pct DESC;HAVING SUM(quantity) >= 10 — отсекает рандомные SKU с шумными margins.
Убыточные продукты
SELECT
product_id,
product_name,
revenue,
cogs,
gross_margin_pct,
CASE
WHEN gross_margin_pct < 0 THEN 'LOSING_MONEY'
WHEN gross_margin_pct < 10 THEN 'LOW_MARGIN'
WHEN gross_margin_pct < 30 THEN 'OK'
ELSE 'HIGH_MARGIN'
END AS category
FROM product_margin_summary
WHERE gross_margin_pct < 10
ORDER BY revenue DESC;Negative margin = продукт убыточный. High revenue + negative margin — особенно болезненно (масштабируете убытки).
Mix shift
Как меняется средний margin с продуктовым составом:
WITH monthly_mix AS (
SELECT
DATE_TRUNC('month', order_date)::DATE AS month,
SUM(oi.quantity * oi.unit_price) AS revenue,
SUM(oi.quantity * p.unit_cost) AS cogs,
SUM(oi.quantity * (oi.unit_price - p.unit_cost))::NUMERIC * 100
/ NULLIF(SUM(oi.quantity * oi.unit_price), 0) AS blended_margin_pct
FROM order_items oi
JOIN products p USING (product_id)
WHERE order_date >= CURRENT_DATE - INTERVAL '12 months'
GROUP BY DATE_TRUNC('month', order_date)
)
SELECT * FROM monthly_mix ORDER BY month;Падение average margin без individual SKU margin changes = mix shifted в сторону low-margin.
Частые ошибки
Ошибка 1. COGS не fully loaded. Помимо raw materials, COGS должна включать direct labor + manufacturing overhead. «Material-only COGS» завышает margin.
Ошибка 2. Allocated overhead. Office rent — не COGS. Это OpEx. Не путать.
Ошибка 3. FX timing. Multi-currency: revenue в момент sale, cost в момент purchase. Если currency двигалась — distortion.
Ошибка 4. Returns reducing revenue, not cogs. Return снижает revenue, но cost (производство) уже понесён. Net margin меньше.
Ошибка 5. Bulk discount in COGS. Если supplier даёт volume discount — фактическая cost ниже invoice. Use net price.
Связанные темы
- Как посчитать gross margin в SQL
- Как посчитать contribution margin в SQL
- Как посчитать COGS в SQL
- Как посчитать net margin в SQL
FAQ
Какой gross margin хороший?
SaaS: 70-85%. E-com: 30-50%. Manufacturing: 25-40%. Restaurants: 60-70% food, 20-30% labor.
Negative margin когда выгодно?
Loss leader (как iPad с low margin + accessories). Customer acquisition tool.
Margin vs markup?
Margin = profit / revenue. Markup = profit / cost. На 50% margin = 100% markup.
Standard vs actual COGS?
Standard — planned. Actual — фактический. Variance показывает procurement issues.
По channel margin?
Channels часто имеют разный mix. Compute by channel и сравнивайте.