Verificar uma consulta SQL escrita por IA com resultados do SQLite calculados à mão
Trate uma consulta SQL gerada por IA como um rascunho e teste-a em um pequeno banco SQLite com respostas conhecidas. Compare o resultado da IA com uma tabela esperada calculada manualmente antes de usar a consulta em dados reais.
Conteúdo verificado 2026.09.20Inclui arquivos de exemplo
Ver o sumário
A tradução foi feita com IA. Confira o código, as unidades e os valores junto com o original. A revisão por falantes nativos de cada idioma ainda não foi concluída. English
Para quem éEste guia é para quem usa IA para criar rascunhos de SQL e quer um teste pequeno e reproduzível antes de executar a consulta em dados importantes.
Preparação
Python 3.12 e um comando de terminal que inicie essa versão.
Uma pasta de trabalho em que os scripts possam criar pastas dentro de outputs.
Familiaridade básica com SELECT, JOIN, GROUP BY e funções de agregação.
É necessária apenas a biblioteca padrão do Python: csv, pathlib e sqlite3.
01Defina a pergunta de negócio antes de revisar o SQL
Suponha que o requisito seja: para cada cliente, informar o valor total dos pedidos PAID feitos durante agosto de 2026. Clientes sem pedidos que atendam às condições ainda devem aparecer com total 0.
Um assistente de IA propõe um INNER JOIN entre customers e orders, seguido de condições WHERE para status e date. A consulta parece razoável, mas o INNER JOIN remove clientes que não têm linhas de pedido correspondentes. Isso viola o requisito de incluir clientes com total zero.
02Crie um banco de dados SQLite sintético
O banco de dados a seguir é sintético e foi criado especificamente para este artigo. Ele tem três clientes e seis pedidos escolhidos para testar status pagos e não pagos, limites entre meses e um cliente sem pedido PAID em agosto.
Ana tem dois pedidos PAID em agosto: 40 e 60, então o total dela é 100. O pedido CANCELLED não conta. Ben tem um pedido válido em agosto no valor de 25; o pedido de setembro não conta. Cara tem apenas um pedido CANCELLED em agosto, então ainda precisa aparecer com 0.
customer_id
customer_name
Total PAID esperado de agosto
1
Ana
100
2
Ben
25
3
Cara
0
O total geral esperado é 125. Deve haver exatamente 3 linhas de saída porque o requisito diz que todos os clientes devem aparecer.
04Compare a consulta da IA com uma consulta revisada
A consulta da IA abaixo filtra os pedidos válidos na cláusula WHERE depois de um INNER JOIN. Cara não tem nenhum pedido PAID em agosto que corresponda, então desaparece completamente.
sql
SELECT
c.customer_id,
c.customer_name,
SUM(o.amount) AS august_paid_total
FROM customers AS c
JOIN orders AS o
ON o.customer_id = c.customer_id
WHERE o.status = 'PAID'
AND o.order_date >= '2026-08-01'
AND o.order_date < '2026-09-01'
GROUP BY c.customer_id, c.customer_name
ORDER BY c.customer_id;
A consulta revisada parte de todos os clientes e usa LEFT JOIN. Os filtros de pedidos são colocados dentro da condição ON para que clientes sem correspondência sejam mantidos. COALESCE converte o agregado NULL resultante em 0.
sql
SELECT
c.customer_id,
c.customer_name,
COALESCE(SUM(o.amount), 0) AS august_paid_total
FROM customers AS c
LEFT JOIN orders AS o
ON o.customer_id = c.customer_id
AND o.status = 'PAID'
AND o.order_date >= '2026-08-01'
AND o.order_date < '2026-09-01'
GROUP BY c.customer_id, c.customer_name
ORDER BY c.customer_id;
05Execute as duas consultas e compare com as linhas esperadas
Salve o script a seguir como ai_sql_check.py. Ele executa as duas consultas, compara os resultados com a tabela esperada calculada à mão e grava um relatório CSV de revisão. O banco sintético não é modificado.
python
import csv
import sqlite3
from pathlib import Path
DATABASE = Path("outputs") / "ai_sql_demo" / "orders.sqlite"
OUTPUT_DIR = Path("outputs") / "ai_sql_check_result"
REPORT = OUTPUT_DIR / "sql_check.csv"
AI_SQL = """
SELECT c.customer_id, c.customer_name, SUM(o.amount)
FROM customers AS c
JOIN orders AS o ON o.customer_id = c.customer_id
WHERE o.status = 'PAID'
AND o.order_date >= '2026-08-01'
AND o.order_date < '2026-09-01'
GROUP BY c.customer_id, c.customer_name
ORDER BY c.customer_id;
"""
REVISED_SQL = """
SELECT c.customer_id, c.customer_name, COALESCE(SUM(o.amount), 0)
FROM customers AS c
LEFT JOIN orders AS o
ON o.customer_id = c.customer_id
AND o.status = 'PAID'
AND o.order_date >= '2026-08-01'
AND o.order_date < '2026-09-01'
GROUP BY c.customer_id, c.customer_name
ORDER BY c.customer_id;
"""
EXPECTED = [
(1, "Ana", 100),
(2, "Ben", 25),
(3, "Cara", 0),
]
def run_query(connection, sql):
return connection.execute(sql).fetchall()
def main() -> None:
if not DATABASE.is_file():
raise FileNotFoundError(f"Database not found: {DATABASE}")
if OUTPUT_DIR.exists():
raise FileExistsError(f"Output folder already exists: {OUTPUT_DIR}")
connection = sqlite3.connect(f"file:{DATABASE.resolve()}?mode=ro", uri=True)
try:
ai_rows = run_query(connection, AI_SQL)
revised_rows = run_query(connection, REVISED_SQL)
finally:
connection.close()
OUTPUT_DIR.parent.mkdir(parents=True, exist_ok=True)
OUTPUT_DIR.mkdir()
with REPORT.open("x", encoding="utf-8", newline="") as stream:
writer = csv.writer(stream)
writer.writerow(["query", "rows", "matches_expected"])
writer.writerow(["AI", repr(ai_rows), ai_rows == EXPECTED])
writer.writerow(["REVISED", repr(revised_rows), revised_rows == EXPECTED])
print(f"Expected rows: {len(EXPECTED)}.")
print(f"AI rows: {len(ai_rows)}; matches expected: {ai_rows == EXPECTED}.")
print(
f"Revised rows: {len(revised_rows)}; "
f"matches expected: {revised_rows == EXPECTED}."
)
print(f"Report: {REPORT.as_posix()}")
if revised_rows != EXPECTED:
raise RuntimeError("Revised SQL does not match the expected result.")
if __name__ == "__main__":
main()
text
python ai_sql_check.py
06Confira a saída esperada
A consulta da IA deve retornar apenas Ana e Ben, produzindo 2 linhas e não correspondendo ao resultado esperado. A consulta revisada deve retornar todos os 3 clientes e corresponder exatamente à tabela calculada à mão.
Consulta
Linhas retornadas
Total geral esperado
Corresponde à tabela esperada
IA
2
125
Não
Revisada
3
125
Sim
O resultado da IA ainda pode ter o total geral correto de 125 mesmo estando errado, porque a linha obrigatória de Cara com valor zero está ausente. Por isso, verificar apenas os totais é insuficiente.
Inclua clientes com zero registros correspondentes nos dados sintéticos quando o requisito disser que eles devem aparecer.
Teste limites de data como August 31 e September 1.
Inclua status excluídos, como CANCELLED.
Execute o verificador novamente sem alterar OUTPUT_DIR. Ele deve parar com FileExistsError em vez de sobrescrever o relatório.
Problema comum
O que verificar
Linhas ausentes inesperadamente
Confira o tipo de JOIN e se filtros em WHERE removem linhas não correspondentes de um LEFT JOIN.
Totais altos demais
Procure joins um-para-muitos que dupliquem linhas antes da agregação.
Intervalo de datas incorreto
Use um limite inferior explícito e um limite superior exclusivo adequado ao formato de data armazenado.
NULL em vez de zero
Decida se correspondências ausentes devem permanecer NULL ou ser convertidas com COALESCE.
Total correto, mas detalhes errados
Compare todas as linhas esperadas, não apenas o total geral.
Este teste comprova apenas que a consulta revisada corresponde a este pequeno exemplo sintético. Esquemas reais podem conter relações duplicadas, valores NULL, timestamps, time zones, refunds ou regras de negócio adicionais. Amplie os dados de teste sempre que essas condições forem importantes.
O total válido de Ana em agosto foi calculado manualmente como 40 + 60 = 100.
O total válido de Ben em agosto foi calculado manualmente como 25, excluindo o pedido de setembro.
Foi determinado manualmente que Cara deve aparecer com 0 porque seu único pedido de agosto é CANCELLED.
O total geral esperado foi calculado manualmente como 125 e a quantidade esperada de linhas como 3.
A consulta da IA foi inspecionada e foi determinado que o INNER JOIN e os filtros WHERE omitem Cara, produzindo 2 linhas.
A consulta revisada com LEFT JOIN foi inspecionada e esperava-se que retornasse as três linhas calculadas à mão.
A saída esperada do console e a comparação do relatório foram derivadas manualmente.
Limites da verificação
O autor desta resposta não executou o código; o comportamento do SQLite e do sistema de arquivos não foi testado aqui.
Apenas as linhas sintéticas listadas foram avaliadas; valores NULL em amount, joins duplicados, timestamps, time zones, refunds e conjuntos grandes não foram testados.
Corresponder a este exemplo não prova que a consulta esteja correta para todo esquema de produção ou regra de negócio.
As URLs da documentação oficial foram fornecidas a partir de locais conhecidos, mas não foram verificadas em tempo real.
Transforme “automatize isso” em uma descrição de tarefa executável. Anexe uma amostra sintética sem dados sensíveis e um resultado esperado verificado manualmente para completar uma solicitação de script que totaliza registros de trabalho por equipe.
Verifique uma função de agregação com quatro linhas que você pode calcular manualmente e 12 unit tests. Verifique não apenas valores normais, mas também entrada vazia, zero, decimais e entrada inválida.
Separe um resumo plausível em fatos, cálculos e interpretações. Recalcule proporções e médias a partir de dados mensais sintéticos e reescreva frases com fontes ausentes ou causas exageradas como afirmações que possam ser verificadas.
Trate uma regex gerada por IA como um rascunho, não como uma regra final. Monte uma pequena tabela de testes sintéticos, compare os resultados esperados com as correspondências reais, revise o padrão e salve um relatório de revisão antes de usá-lo em dados reais.