SQL na Prática: Resolvendo 5 Problemas Reais de Negócio
Na jornada de um analista de dados, a habilidade de transformar perguntas de negócio em consultas SQL eficientes é um verdadeiro diferencial. Diariamente, profissionais de dados precisam responder questões complexas que impactam diretamente as decisões estratégicas das empresas.
Neste artigo, vamos explorar cinco cenários reais de negócio e como resolvê-los usando SQL. Você verá que, com as técnicas certas, é possível extrair insights valiosos que podem impulsionar resultados em diferentes áreas.
1. Análise de Retenção de Clientes: Calculando a Taxa de Churn Mensal
O problema: Uma empresa de software SaaS precisa entender sua taxa de churn (cancelamento) mensal para identificar tendências e tomar medidas proativas.
A solução: Usando SQL, podemos calcular a porcentagem de clientes que cancelam suas assinaturas a cada mês.
WITH monthly_active_users AS (
SELECT
DATE_TRUNC('month', date) AS month,
COUNT(DISTINCT user_id) AS active_users
FROM subscriptions
WHERE status = 'active'
GROUP BY DATE_TRUNC('month', date)
),
monthly_churned_users AS (
SELECT
DATE_TRUNC('month', cancellation_date) AS month,
COUNT(DISTINCT user_id) AS churned_users
FROM subscriptions
WHERE status = 'cancelled'
GROUP BY DATE_TRUNC('month', cancellation_date)
)
SELECT
a.month,
a.active_users,
COALESCE(c.churned_users, 0) AS churned_users,
ROUND((COALESCE(c.churned_users, 0)::FLOAT / a.active_users) * 100, 2) AS churn_rate
FROM monthly_active_users a
LEFT JOIN monthly_churned_users c ON a.month = c.month
ORDER BY a.month;Esta consulta primeiro identifica os usuários ativos e os que cancelaram em cada mês. Depois, calcula a taxa de churn como a porcentagem de usuários que cancelaram em relação aos usuários ativos. O resultado é uma visão mensal que permite identificar picos de cancelamento para investigação posterior.
2. Análise de Funil de Conversão: Do Registro à Compra
O problema: Um e-commerce precisa entender como os usuários progridem em seu funil de conversão, desde o registro até a finalização da compra.
A solução: Criamos um funil que rastreia a jornada do usuário através de eventos-chave e calcula as taxas de conversão entre etapas.
WITH user_stages AS (
SELECT
user_id,
MIN(CASE WHEN event_name = 'signup' THEN event_timestamp END) AS signup_time,
MIN(CASE WHEN event_name = 'product_view' THEN event_timestamp END) AS product_view_time,
MIN(CASE WHEN event_name = 'add_to_cart' THEN event_timestamp END) AS add_to_cart_time,
MIN(CASE WHEN event_name = 'checkout_start' THEN event_timestamp END) AS checkout_start_time,
MIN(CASE WHEN event_name = 'purchase' THEN event_timestamp END) AS purchase_time
FROM user_events
WHERE event_timestamp >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY user_id
),
stage_counts AS (
SELECT
COUNT(DISTINCT user_id) AS signup_count,
COUNT(DISTINCT CASE WHEN product_view_time IS NOT NULL THEN user_id END) AS product_view_count,
COUNT(DISTINCT CASE WHEN add_to_cart_time IS NOT NULL THEN user_id END) AS add_to_cart_count,
COUNT(DISTINCT CASE WHEN checkout_start_time IS NOT NULL THEN user_id END) AS checkout_start_count,
COUNT(DISTINCT CASE WHEN purchase_time IS NOT NULL THEN user_id END) AS purchase_count
FROM user_stages
)
SELECT
signup_count,
product_view_count,
ROUND((product_view_count::FLOAT / NULLIF(signup_count, 0)) * 100, 2) AS signup_to_view_rate,
add_to_cart_count,
ROUND((add_to_cart_count::FLOAT / NULLIF(product_view_count, 0)) * 100, 2) AS view_to_cart_rate,
checkout_start_count,
ROUND((checkout_start_count::FLOAT / NULLIF(add_to_cart_count, 0)) * 100, 2) AS cart_to_checkout_rate,
purchase_count,
ROUND((purchase_count::FLOAT / NULLIF(checkout_start_count, 0)) * 100, 2) AS checkout_to_purchase_rate,
ROUND((purchase_count::FLOAT / NULLIF(signup_count, 0)) * 100, 2) AS overall_conversion_rate
FROM stage_counts;Esta análise identifica os gargalos no funil de conversão, permitindo que a equipe foque em melhorar os estágios com maior taxa de abandono. Por exemplo, se a taxa de conversão do "carrinho para checkout" for muito baixa, pode indicar problemas no processo de pagamento.
3. Segmentação de Clientes por RFM (Recência, Frequência, Valor Monetário)
O problema: Uma empresa de varejo quer segmentar seus clientes para campanhas de marketing personalizadas com base em seus comportamentos de compra.
A solução: Implementamos uma análise RFM (Recência, Frequência, Valor Monetário) usando SQL.
WITH rfm_data AS (
SELECT
customer_id,
CURRENT_DATE - MAX(order_date) AS recency,
COUNT(order_id) AS frequency,
SUM(order_value) AS monetary
FROM orders
WHERE order_date >= CURRENT_DATE - INTERVAL '1 year'
GROUP BY customer_id
),
rfm_scores AS (
SELECT
customer_id,
NTILE(5) OVER (ORDER BY recency DESC) AS recency_score,
NTILE(5) OVER (ORDER BY frequency) AS frequency_score,
NTILE(5) OVER (ORDER BY monetary) AS monetary_score
FROM rfm_data
),
rfm_final AS (
SELECT
customer_id,
recency_score,
frequency_score,
monetary_score,
recency_score * 100 + frequency_score * 10 + monetary_score AS rfm_score
FROM rfm_scores
)
SELECT
customer_id,
CASE
WHEN rfm_score >= 500 THEN 'Champions'
WHEN rfm_score >= 400 THEN 'Loyal Customers'
WHEN rfm_score >= 300 THEN 'Potential Loyalists'
WHEN recency_score >= 4 AND (frequency_score + monetary_score) <= 4 THEN 'New Customers'
WHEN recency_score <= 2 AND (frequency_score + monetary_score) <= 4 THEN 'At Risk'
WHEN recency_score <= 2 AND (frequency_score + monetary_score) <= 2 THEN 'Lost'
ELSE 'Regular Customers'
END AS customer_segment,
recency_score,
frequency_score,
monetary_score,
rfm_score
FROM rfm_final
ORDER BY rfm_score DESC;Esta consulta atribui pontuações de 1 a 5 para cada dimensão RFM e depois combina essas pontuações para categorizar os clientes em segmentos significativos. Isso permite estratégias de marketing personalizadas - por exemplo, oferecendo incentivos de reativação aos clientes "At Risk" ou programas de fidelidade aos "Champions".
4. Detecção de Anomalias em Vendas Diárias
O problema: Um negócio de varejo precisa identificar rapidamente dias com vendas anormalmente altas ou baixas para investigar possíveis problemas ou oportunidades.
A solução: Usamos estatísticas básicas para calcular limites e identificar outliers.
WITH daily_sales AS (
SELECT
order_date,
SUM(order_value) AS daily_revenue
FROM orders
WHERE order_date >= CURRENT_DATE - INTERVAL '90 days'
GROUP BY order_date
),
sales_stats AS (
SELECT
AVG(daily_revenue) AS avg_revenue,
STDDEV(daily_revenue) AS stddev_revenue
FROM daily_sales
)
SELECT
d.order_date,
d.daily_revenue,
s.avg_revenue,
s.stddev_revenue,
(d.daily_revenue - s.avg_revenue) / s.stddev_revenue AS z_score,
CASE
WHEN (d.daily_revenue - s.avg_revenue) / s.stddev_revenue > 2 THEN 'Unusually High'
WHEN (d.daily_revenue - s.avg_revenue) / s.stddev_revenue < -2 THEN 'Unusually Low'
ELSE 'Normal'
END AS sales_pattern
FROM daily_sales d
CROSS JOIN sales_stats s
WHERE ABS((d.daily_revenue - s.avg_revenue) / s.stddev_revenue) > 2
ORDER BY ABS((d.daily_revenue - s.avg_revenue) / s.stddev_revenue) DESC;Esta análise usa o desvio padrão para identificar dias com receita significativamente diferente da média (usando z-scores). Valores anormalmente altos podem indicar promoções bem-sucedidas, enquanto valores baixos podem apontar problemas no site ou na disponibilidade de produtos.
5. Análise de Coorte para Retenção de Usuários
O problema: Uma empresa SaaS precisa entender como a retenção varia entre diferentes coortes de usuários (agrupados pelo mês em que se inscreveram).
A solução: Criamos uma análise de coorte usando SQL para acompanhar a retenção ao longo do tempo.
WITH user_cohorts AS (
SELECT
user_id,
DATE_TRUNC('month', MIN(subscription_start_date)) AS cohort_month
FROM subscriptions
GROUP BY user_id
),
user_activity AS (
SELECT
u.user_id,
u.cohort_month,
DATE_TRUNC('month', a.activity_date) AS activity_month,
DATE_PART('month', AGE(DATE_TRUNC('month', a.activity_date), u.cohort_month)) AS month_number
FROM user_cohorts u
JOIN user_activity_logs a ON u.user_id = a.user_id
WHERE a.activity_date >= u.cohort_month
),
cohort_size AS (
SELECT
cohort_month,
COUNT(DISTINCT user_id) AS users
FROM user_cohorts
GROUP BY cohort_month
),
retention_data AS (
SELECT
cohort_month,
month_number,
COUNT(DISTINCT user_id) AS active_users
FROM user_activity
GROUP BY cohort_month, month_number
)
SELECT
TO_CHAR(r.cohort_month, 'YYYY-MM') AS cohort,
c.users AS cohort_size,
r.month_number,
r.active_users,
ROUND((r.active_users::FLOAT / c.users) * 100, 2) AS retention_rate
FROM retention_data r
JOIN cohort_size c ON r.cohort_month = c.cohort_month
ORDER BY r.cohort_month, r.month_number;Esta análise permite comparar a retenção de diferentes coortes de usuários ao longo do tempo. Você pode identificar, por exemplo, se usuários que se inscreveram durante períodos promocionais têm menor retenção a longo prazo, ou se melhorias no produto resultaram em maior retenção para coortes mais recentes.
Conclusão
Estas consultas SQL demonstram como podemos transformar perguntas de negócio complexas em insights acionáveis. Ao dominar estas técnicas, você pode elevar seu valor como analista de dados, fornecendo não apenas relatórios básicos, mas análises estratégicas que impulsionam decisões de negócio.
Lembre-se de que cada empresa tem suas próprias estruturas de dados e necessidades específicas, então você precisará adaptar estas consultas à sua realidade. A chave está em entender o problema de negócio primeiro, e depois desenhar a solução SQL adequada.
Quer aprofundar seus conhecimentos em SQL para análise de dados? Confira nosso curso completo SQL para Análise de Dados, onde abordamos estas e muitas outras técnicas avançadas.
E você, já utilizou SQL para resolver algum problema complexo de negócio? Compartilhe sua experiência nos comentários!