Para fazer análises de dados com SQL no dia a dia, o “ambiente de trabalho” é a combinação de: onde os dados ficam armazenados, como você acessa esses dados, como organiza consultas e resultados, e quais práticas garantem que suas análises sejam reproduzíveis e confiáveis. Já os “conjuntos de dados” (datasets) são as tabelas e visões que você consulta para responder perguntas do negócio: vendas, estoque, atendimento, marketing, finanças, produto, logística. Neste capítulo, o foco é montar um ambiente prático e escolher/estruturar datasets que facilitem relatórios e insights recorrentes.
O que compõe um ambiente de trabalho para análises com SQL
Um ambiente de trabalho típico para análise com SQL envolve quatro camadas: armazenamento, acesso, organização e governança. Você pode ter tudo em um único sistema ou distribuído, mas o importante é que o fluxo seja previsível.
1) Armazenamento (onde os dados vivem)
Os dados normalmente vivem em um banco relacional (PostgreSQL, MySQL, SQL Server), em um data warehouse (como BigQuery, Snowflake, Redshift) ou em um lake/lakehouse. Para análises do dia a dia, o ponto central é: você precisa saber qual é a “fonte de verdade” para cada assunto (ex.: pedidos, clientes, pagamentos) e qual é a latência aceitável (dados em tempo real, a cada hora, diariamente).
- Banco transacional (OLTP): otimizado para operações do sistema (cadastros, pedidos). Pode ser consultado, mas costuma exigir cuidado para não impactar performance.
- Warehouse (OLAP): otimizado para leitura e agregações. Geralmente é o melhor lugar para relatórios e análises recorrentes.
- Camadas (bronze/silver/gold): uma forma comum de organizar dados por maturidade: bruto, tratado e pronto para consumo.
2) Acesso (como você consulta)
Você pode consultar via um editor SQL (IDE), via notebooks, via ferramentas de BI ou via scripts. Independentemente da ferramenta, o que importa é ter: credenciais, permissões adequadas, e um padrão de conexão (host, database, schema) que evite confusões entre ambientes (produção, homologação, desenvolvimento).
- Ambiente de produção: contém dados reais e é sensível. Idealmente, análises pesadas devem rodar em réplicas/warehouse.
- Ambiente de desenvolvimento: usado para testar queries e criar tabelas auxiliares sem risco.
- Ambiente de sandbox: espaço pessoal ou do time para experimentos, com limites e limpeza periódica.
3) Organização (como você guarda e reaproveita consultas)
Para análises do dia a dia, o ganho de produtividade vem de reaproveitar consultas e padronizar saídas. Em vez de “consultas soltas”, pense em um repositório de queries com nomes, comentários e versões.
Continue em nosso aplicativo
Você poderá ouvir o audiobook com a tela desligada, ganhar gratuitamente o certificado deste curso e ainda ter acesso a outros 5.000 cursos online gratuitos.
ou continue lendo abaixo...Baixar o aplicativo
- Biblioteca de queries: consultas frequentes (ex.: receita diária, funil, churn) com parâmetros claros.
- Views: encapsulam lógica comum e reduzem repetição.
- Tabelas derivadas: tabelas de apoio (ex.: calendário, metas) e tabelas agregadas para performance.
4) Governança (qualidade, segurança e rastreabilidade)
Mesmo em análises rápidas, governança evita retrabalho e erros. O mínimo viável inclui: dicionário de dados, convenções de nomes, controle de acesso e checagens simples de qualidade (valores nulos, duplicidades, chaves).
- Permissões por schema: separar consumo (read) de transformação (write).
- Auditoria: saber quem alterou uma view/tabela e quando.
- Qualidade: regras simples como “pedido deve ter customer_id” e “data de pagamento não pode ser anterior ao pedido”.
Como escolher conjuntos de dados para análises do dia a dia
Um conjunto de dados “bom para análise” não é apenas uma tabela grande. Ele precisa ser compreensível, consistente e alinhado às perguntas que você responde com frequência. Para escolher datasets, pense em três dimensões: cobertura, granularidade e confiabilidade.
Cobertura: quais processos do negócio estão representados
Mapeie os processos que geram dados e que você precisa medir. Um mapeamento simples costuma incluir:
- Clientes: cadastro, segmentação, status, origem.
- Pedidos/Vendas: itens, valores, descontos, impostos, frete.
- Pagamentos: método, status, chargeback, datas.
- Produtos: catálogo, categorias, custo, margem.
- Atendimento: tickets, motivos, SLA, satisfação.
- Marketing: campanhas, cliques, conversões (quando disponível).
Nem sempre tudo estará no mesmo banco. O ideal é ter uma camada consolidada (warehouse) com chaves que permitam cruzar assuntos (ex.: customer_id, order_id, product_id).
Granularidade: o nível de detalhe correto
Granularidade é o “nível de linha” de uma tabela. Para análises diárias, você normalmente precisa de tabelas em granularidades complementares:
- Fato de pedidos (1 linha por pedido): boa para receita, contagem de pedidos, ticket médio.
- Fato de itens (1 linha por item do pedido): boa para mix de produtos, margem por categoria.
- Eventos (1 linha por evento): boa para funis e comportamento (quando existe).
- Dimensões (1 linha por entidade): clientes, produtos, calendário.
Um erro comum é tentar responder tudo a partir da tabela mais detalhada (itens ou eventos) e acabar duplicando valores (ex.: somar receita do pedido repetida por item). Ter tabelas de fatos separadas por granularidade reduz esse risco.
Confiabilidade: consistência e regras de negócio
Antes de usar um dataset como base de relatório, valide:
- Chaves: existe uma chave primária clara? order_id é único na tabela de pedidos?
- Datas: qual data representa o quê? data_criacao, data_pagamento, data_envio.
- Status: quais status existem e quais entram em “venda concluída”?
- Atualização: a tabela é incremental? pode sofrer alterações retroativas?
Essa validação vira um checklist que você repete sempre que um novo dataset entra no seu radar.
Estrutura recomendada de schemas para análise
Uma organização simples por schemas ajuda a separar responsabilidades e a reduzir confusão. Um exemplo de estrutura:
- raw: dados brutos, como chegaram da fonte.
- staging: dados limpos e padronizados (tipos, colunas, deduplicação).
- analytics: tabelas e views prontas para consumo (métricas, dimensões conformadas).
- sandbox: experimentos e tabelas temporárias do time.
Mesmo que você não tenha controle sobre a ingestão, você pode aplicar essa lógica criando views ou tabelas derivadas em um schema de analytics.
Conjunto de dados “mínimo viável” para relatórios recorrentes
Para a maioria das rotinas de análise, um conjunto mínimo viável costuma incluir: uma dimensão de calendário, uma dimensão de clientes, uma dimensão de produtos e pelo menos uma tabela fato de pedidos e outra de pagamentos. A seguir, um modelo prático (colunas sugeridas) para você reconhecer ou construir no seu ambiente.
Dimensão calendário (dim_date)
Uma tabela de calendário evita gambiarras com funções de data e facilita relatórios por semana/mês, comparações e preenchimento de datas sem movimento.
-- Exemplo de estrutura (colunas comuns em dim_date): date_day, year, month, month_name, week_of_year, is_weekendDimensão clientes (dim_customer)
Deve conter atributos relativamente estáveis e úteis para segmentação.
-- customer_id (chave), created_at, country, state, city, acquisition_channel, customer_statusDimensão produtos (dim_product)
Ajuda a analisar mix, categorias e margem (quando disponível).
-- product_id (chave), product_name, category, subcategory, brand, cost, is_activeFato pedidos (fact_orders)
Uma linha por pedido, com métricas no nível do pedido.
-- order_id (chave), customer_id, order_created_at, order_status, gross_amount, discount_amount, net_amount, shipping_amountFato itens (fact_order_items)
Uma linha por item do pedido, com quantidade e valores por item.
-- order_id, order_item_id (chave), product_id, quantity, item_gross_amount, item_discount_amount, item_net_amountFato pagamentos (fact_payments)
Uma linha por transação de pagamento (pode haver mais de uma por pedido).
-- payment_id (chave), order_id, payment_method, payment_status, paid_at, amountCom esse conjunto, você cobre boa parte das perguntas do dia a dia: receita por período, pedidos por status, ticket médio, top produtos, conversão pagamento, inadimplência/pendências, recorrência por cliente.
Passo a passo prático: preparar seu ambiente para análises recorrentes
A seguir, um passo a passo que você pode aplicar em praticamente qualquer banco SQL. A ideia é sair de “consultas pontuais” para um ambiente onde relatórios são fáceis de manter.
Passo 1: identificar as tabelas fonte e suas chaves
Liste as tabelas disponíveis e identifique chaves e relacionamentos. Se você tiver acesso ao catálogo do banco, comece por lá. Caso não tenha, use consultas exploratórias.
-- Ver amostra de colunas e dados (ajuste LIMIT conforme o banco SQL usado)SELECT * FROM orders LIMIT 20;SELECT * FROM order_items LIMIT 20;SELECT * FROM customers LIMIT 20;Valide unicidade de chaves candidatas. Exemplo: order_id deve ser único em orders.
SELECT order_id, COUNT(*) AS qtdFROM ordersGROUP BY order_idHAVING COUNT(*) > 1;Passo 2: padronizar tipos e nomes em uma camada de staging
Mesmo que você não crie tabelas físicas, crie views de staging para padronizar: nomes de colunas, tipos de data, flags e status. Isso reduz divergência entre análises.
CREATE VIEW staging.stg_orders ASSELECT CAST(order_id AS BIGINT) AS order_id, CAST(customer_id AS BIGINT) AS customer_id, CAST(created_at AS TIMESTAMP) AS order_created_at, LOWER(TRIM(status)) AS order_status, CAST(gross_amount AS NUMERIC(18,2)) AS gross_amount, CAST(discount_amount AS NUMERIC(18,2)) AS discount_amount, CAST(net_amount AS NUMERIC(18,2)) AS net_amount, CAST(shipping_amount AS NUMERIC(18,2)) AS shipping_amountFROM raw.orders;Se o seu banco não permitir criar view, você pode manter essa padronização em uma query “base” que será reutilizada.
Passo 3: criar dimensões conformadas (clientes, produtos, calendário)
Dimensões conformadas são dimensões usadas de forma consistente em relatórios. Comece com clientes e produtos. Se houver duplicidade na fonte (ex.: múltiplos registros por customer_id), defina uma regra de deduplicação.
CREATE VIEW analytics.dim_customer ASSELECT customer_id, MIN(created_at) AS created_at, MAX(country) AS country, MAX(state) AS state, MAX(city) AS city, MAX(acquisition_channel) AS acquisition_channel, MAX(status) AS customer_statusFROM staging.stg_customersGROUP BY customer_id;Para calendário, se você não tiver uma tabela pronta, pode criar uma tabela física (recomendado) ou uma view baseada em uma tabela de números/gerador de datas (depende do banco). O importante é ter colunas como mês, semana, trimestre e indicadores úteis.
Passo 4: separar fatos por granularidade e evitar duplicações
Crie uma visão “fato pedidos” e outra “fato itens”. Evite misturar itens com pedidos em uma única tabela sem cuidado, porque isso duplica valores do pedido ao juntar com itens.
CREATE VIEW analytics.fact_orders ASSELECT order_id, customer_id, order_created_at, order_status, gross_amount, discount_amount, net_amount, shipping_amountFROM staging.stg_orders;CREATE VIEW analytics.fact_order_items ASSELECT order_id, order_item_id, product_id, quantity, item_gross_amount, item_discount_amount, item_net_amountFROM staging.stg_order_items;Passo 5: criar métricas reutilizáveis via views (camada “gold”)
Em vez de reescrever a mesma lógica de “receita líquida por dia” em todo relatório, crie uma view de métricas diárias. Isso também facilita auditoria.
CREATE VIEW analytics.vw_daily_revenue ASSELECT CAST(order_created_at AS DATE) AS date_day, SUM(net_amount) AS net_revenue, COUNT(DISTINCT order_id) AS orders, COUNT(DISTINCT customer_id) AS customersFROM analytics.fact_ordersWHERE order_status IN ('paid','completed')GROUP BY CAST(order_created_at AS DATE);Se o seu negócio reconhece receita na data de pagamento (e não na criação do pedido), crie uma métrica alternativa baseada em pagamentos, deixando explícito o critério.
CREATE VIEW analytics.vw_daily_paid_amount ASSELECT CAST(paid_at AS DATE) AS date_day, SUM(amount) AS paid_amount, COUNT(DISTINCT order_id) AS paid_ordersFROM analytics.fact_paymentsWHERE payment_status = 'paid'GROUP BY CAST(paid_at AS DATE);Passo 6: montar um “dataset de relatório” com joins padronizados
Para relatórios recorrentes, é comum criar uma view já com joins principais, para que o analista foque em filtros e agregações, não em relacionamentos.
CREATE VIEW analytics.vw_orders_enriched ASSELECT o.order_id, o.order_created_at, o.order_status, o.net_amount, o.shipping_amount, c.customer_id, c.country, c.state, c.city, c.acquisition_channelFROM analytics.fact_orders oLEFT JOIN analytics.dim_customer c ON o.customer_id = c.customer_id;Se você precisa de informações de produto, faça isso no nível de itens, não no nível de pedidos.
CREATE VIEW analytics.vw_order_items_enriched ASSELECT i.order_id, i.order_item_id, i.product_id, i.quantity, i.item_net_amount, p.category, p.subcategory, p.brandFROM analytics.fact_order_items iLEFT JOIN analytics.dim_product p ON i.product_id = p.product_id;Passo 7: validar qualidade com checagens rápidas
Antes de confiar em um dataset, rode checagens simples e guarde essas queries como “testes manuais” do time.
- Valores nulos em chaves
SELECT COUNT(*) AS null_customersFROM analytics.fact_ordersWHERE customer_id IS NULL;- Status inesperados
SELECT order_status, COUNT(*) AS qtdFROM analytics.fact_ordersGROUP BY order_statusORDER BY qtd DESC;- Datas fora do intervalo esperado
SELECT MIN(order_created_at) AS min_date, MAX(order_created_at) AS max_dateFROM analytics.fact_orders;- Reconciliação simples: comparar soma de net_amount com outra fonte (quando existir) ou com pagamentos pagos no período, entendendo que podem divergir por timing.
Boas práticas para trabalhar com datasets no dia a dia
Documente o significado das colunas críticas
Em análises recorrentes, as mesmas dúvidas voltam: “net_amount inclui frete?”, “status completed é entregue ou pago?”. Mantenha um dicionário simples (mesmo que seja em comentários nas views) com definições e regras.
-- Exemplo de comentário (quando suportado):-- net_amount: valor após descontos; não inclui shipping_amountPadronize nomes e convenções
Escolha um padrão e mantenha: prefixos para dimensões e fatos, nomes em snake_case, datas com sufixo _at (timestamp) e _date (date). Isso reduz erros e acelera leitura.
- dim_ para dimensões: dim_customer, dim_product
- fact_ para fatos: fact_orders, fact_payments
- vw_ para views de consumo: vw_daily_revenue
Evite “SELECT *” em views de consumo
Em datasets de relatório, selecione explicitamente as colunas. Isso evita que mudanças na fonte quebrem relatórios ou incluam colunas inesperadas.
Crie tabelas auxiliares para o que o negócio usa sempre
Alguns exemplos comuns:
- Tabela de metas: meta por mês, por canal, por região.
- Tabela de feriados: para análises de sazonalidade.
- Tabela de mapeamentos: normalização de categorias, agrupamentos de status, equivalências.
Essas tabelas geralmente são pequenas, mas aumentam muito a consistência dos relatórios.
Trate mudanças de definição como versões
Quando uma métrica muda (ex.: receita passa a considerar apenas pedidos pagos), evite “trocar silenciosamente” a lógica. Crie uma nova view (ex.: vw_daily_revenue_v2) ou registre a mudança com data e motivo. Isso evita divergência em relatórios históricos.
Exemplos práticos de perguntas do dia a dia e quais datasets usar
Receita e pedidos por dia (visão executiva)
Use a view de receita diária (ou fact_orders com dim_date). Se precisar preencher dias sem vendas, junte com dim_date.
SELECT d.date_day, COALESCE(r.net_revenue, 0) AS net_revenue, COALESCE(r.orders, 0) AS ordersFROM analytics.dim_date dLEFT JOIN analytics.vw_daily_revenue r ON d.date_day = r.date_dayWHERE d.date_day BETWEEN DATE '2025-01-01' AND DATE '2025-01-31'ORDER BY d.date_day;Top categorias por valor vendido (mix de produtos)
Use itens enriquecidos com produto, agregando por categoria.
SELECT category, SUM(item_net_amount) AS net_amount, SUM(quantity) AS unitsFROM analytics.vw_order_items_enrichedGROUP BY categoryORDER BY net_amount DESC;Pedidos pendentes e impacto potencial
Use fact_orders filtrando status e somando valores. Se houver pagamentos, cruze para entender o que está “criado mas não pago”.
SELECT order_status, COUNT(*) AS orders, SUM(net_amount) AS net_amountFROM analytics.fact_ordersWHERE order_status IN ('pending','awaiting_payment','processing')GROUP BY order_statusORDER BY net_amount DESC;Clientes novos por semana e canal
Use dim_customer e dim_date para agrupar por semana e canal.
SELECT d.year, d.week_of_year, c.acquisition_channel, COUNT(*) AS new_customersFROM analytics.dim_customer cJOIN analytics.dim_date d ON CAST(c.created_at AS DATE) = d.date_dayGROUP BY d.year, d.week_of_year, c.acquisition_channelORDER BY d.year, d.week_of_year, new_customers DESC;Checklist rápido para avaliar se um dataset está pronto para uso
- Existe uma chave primária clara e sem duplicidade?
- As colunas de data têm significado definido (criação, pagamento, entrega)?
- Os status estão normalizados e documentados?
- A granularidade está explícita (1 linha por quê)?
- Há dimensões para segmentação (cliente, produto, região, canal)?
- Há checagens básicas de qualidade (nulos, duplicados, intervalos)?
- Existe uma view/tabela de consumo para evitar joins repetitivos?
- O dataset tem dono (time responsável) e frequência de atualização conhecida?