Freecode
  • Claude
  • ChatGPT

SQL a partir da pergunta de negócio

  • 4.7 (6)
  • 7
  • 5
  • Jul 14, 2026

Explicita as decisões escondidas antes de escrever a consulta.

Free

Free. Account required.

Lab

Test how it works before buying.

Prompt

32 lines

## Pergunta de negócio
{{pergunta}}

## Esquema disponível
```sql
{{esquema}}
```

Dialeto: {{dialeto}}

## Etapa 1, decisões escondidas (antes de qualquer SQL)
Liste toda decisão que a pergunta deixa em aberto e que muda o resultado. Típicas:
- Qual data conta: criação, pagamento, competência?
- Fuso horário e onde vira o dia
- O que fazer com registro cancelado, estornado, de teste ou duplicado
- Se o denominador inclui quem entrou no meio do período
- Se valor é bruto ou líquido de imposto e desconto

Para cada decisão: as opções, e qual você escolheu como padrão e por quê.

## Etapa 2, a consulta
SQL comentado, com cada decisão da etapa 1 marcada no ponto onde foi aplicada.
- CTEs nomeadas por significado de negócio, não `t1`, `t2`
- Sem `SELECT *`
- Filtros de data explícitos e inclusivos/exclusivos declarados

## Etapa 3, como conferir
Duas checagens rápidas que provam que o resultado não é absurdo (ordem de grandeza,
total que bate com outra fonte, linha conhecida).

## Etapa 4, armadilhas deste esquema
O que neste esquema específico costuma produzir número errado.

What this prompt does

Traduz uma pergunta ambígua de negócio em SQL, listando primeiro as decisões que o analista teria que tomar no caminho, qual data conta, o que é usuário ativo, como tratar cancelamento. A consulta vem depois, com as escolhas comentadas.

Preview

Result

Etapa 1, decisões escondidas

1. O que é "ativo"? Teve sessão? Tem assinatura ativa? Ambos?
→ Escolhi: teve ao menos uma sessão no período. É a definição de uso, e o esquema tem sessions. Se o time quiser "ativo = pagante", a consulta é outra, e o número será bem menor.

2. Sessão de qualquer duração conta? Uma sessão de 2 segundos é provavelmente um bot ou um toque acidental.
→ Escolhi: duração ≥ 10s. É arbitrário e você deve calibrar, mas não filtrar nada infla o número.

3. Fuso horário. started_at está em UTC ou local? Junho em UTC ≠ junho em São Paulo.
→ Escolhi: converto para America/Sao_Paulo. Se a coluna já estiver em horário local, remova a conversão, aplicá-la duas vezes desloca 3 horas de dados nas bordas do mês.

4. Usuário deletado no meio do mês. Ele usou o produto em junho e saiu no dia 20.
→ Escolhi: conta. Ele foi ativo em junho; o deleted_at posterior não apaga isso. Filtrar por deleted_at IS NULL é o erro mais comum aqui e subestima meses passados de forma crescente.

5. Usuários de teste. is_test existe, então alguém já foi mordido por isso.
→ Escolhi: excluir.

6. Borda do período. 30 de junho às 23h59 conta?
→ Escolhi: intervalo semiaberto >= 01/06 AND < 01/07. Evita o buraco de um segundo que BETWEEN com data cria.

Etapa 2, a consulta

WITH sessoes_do_periodo AS (
  SELECT
    s.user_id,
    s.id AS session_id
  FROM sessions AS s
  WHERE
    -- decisão 3 e 6: fuso local, intervalo semiaberto
    (s.started_at AT TIME ZONE 'UTC' AT TIME ZONE 'America/Sao_Paulo')
      >= DATE '2026-06-01'
    AND (s.started_at AT TIME ZONE 'UTC' AT TIME ZONE 'America/Sao_Paulo')
      < DATE '2026-07-01'
    -- decisão 2: descarta toque acidental e bot
    AND s.duration_s >= 10
),

usuarios_validos AS (
  SELECT u.id
  FROM users AS u
  -- decisão 5: fora os usuários de teste
  WHERE u.is_test = FALSE
  -- decisão 4: NÃO filtramos deleted_at de propósito.
  -- Quem usou em junho foi ativo em junho, mesmo que tenha saído depois.
)

SELECT COUNT(DISTINCT s.user_id) AS usuarios_ativos
FROM sessoes_do_periodo AS s
INNER JOIN usuarios_validos AS u ON u.id = s.user_id;

Etapa 3, como conferir

  1. Ordem de grandeza: rode a mesma consulta para maio e para julho. Um salto acima de 30% entre meses consecutivos quase sempre é erro de consulta, não crescimento real.
  2. Teto lógico: o resultado tem que ser menor que COUNT(*) FROM users WHERE is_test = FALSE AND created_at < '2026-07-01'. Se for maior, há duplicata em sessions.user_id apontando para usuário inexistente, sinal de FK ausente.

Etapa 4, armadilhas deste esquema

  • subscriptions.status não tem histórico. Só existe o estado atual. Você não consegue responder "quantos estavam pagantes em junho" com este esquema, só "quantos estão pagantes hoje e eram usuários em junho". São coisas diferentes, e a segunda não serve para série temporal. Precisa de uma tabela de eventos de assinatura.
  • canceled_at sem started_at da assinatura. Não dá para calcular tempo de vida.
  • Sem índice aparente em sessions.started_at. Em tabela grande, a conversão de fuso dentro do WHERE impede uso de índice. Se demorar, calcule os limites em UTC do lado de fora e compare direto com started_at.

How to use

  1. 1

    Copy the template

    Use the copy button in the block above. It is 32 lines of instruction.

  2. 2

    Fill in the variables

    Swap the 3 highlighted variables for your own content. Leaving them blank degrades the output.

  3. 3

    Pick one of the listed models

    Run it on one of the models listed on the side. A smaller model usually degrades the result.

  4. 4

    Paste and run

    Or use the lab, with your own key, and compare it against the preview.

Performance

Nobody has run this prompt in the lab yet.

Versions

Comments

Sign in to comment

No comments yet.