SQL básico: as consultas essenciais com exemplos práticos
SQL é a linguagem usada para consultar e alterar dados em bancos relacionais como PostgreSQL, MySQL, SQL Server e SQLite. Com meia dúzia de comandos você já consegue responder perguntas reais do negócio: quais pedidos foram feitos este mês, quanto cada cliente gastou, quais produtos vendem mais.
Neste guia você vai ver SELECT, WHERE, ORDER BY, JOIN, GROUP BY, INSERT, UPDATE e DELETE usando sempre o mesmo exemplo, uma loja com tabelas de clientes e pedidos. No final, os cuidados que evitam o erro mais temido de quem está começando: apagar ou alterar a tabela inteira sem querer.
As tabelas do exemplo
Vamos usar duas tabelas. A de clientes guarda quem compra; a de pedidos guarda cada compra e aponta para o cliente pela coluna cliente_id, que é uma chave estrangeira.
CREATE TABLE clientes (
id INTEGER PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
cidade VARCHAR(60)
);
CREATE TABLE pedidos (
id INTEGER PRIMARY KEY,
cliente_id INTEGER NOT NULL REFERENCES clientes(id),
data_pedido DATE NOT NULL,
valor DECIMAL(10,2) NOT NULL,
status VARCHAR(20) NOT NULL
);
Para praticar sem instalar nada pesado, você pode usar o SQLite (um único arquivo) ou subir um PostgreSQL com Docker, como mostramos em Docker para iniciantes. Os comandos deste artigo funcionam nos principais bancos, com pequenas diferenças apontadas quando existirem.
SELECT, WHERE e ORDER BY: lendo dados
O SELECT escolhe as colunas, o FROM indica a tabela, o WHERE filtra as linhas e o ORDER BY ordena o resultado.
-- Todos os pedidos pagos acima de 100 reais, do maior para o menor
SELECT id, cliente_id, data_pedido, valor
FROM pedidos
WHERE status = 'PAGO'
AND valor > 100
ORDER BY valor DESC;
Filtros que você vai usar o tempo todo:
WHERE data_pedido BETWEEN '2026-09-01' AND '2026-09-30': intervalo de datas (inclui as duas pontas).WHERE status IN ('PAGO', 'ENVIADO'): um entre vários valores.WHERE nome LIKE 'Ana%': texto que começa com "Ana". O%representa qualquer sequência de caracteres.WHERE cidade IS NULL: valor ausente. Atenção:cidade = NULLnão funciona, porque NULL não é igual a nada, nem a outro NULL.
Para limitar a quantidade de linhas, PostgreSQL, MySQL e SQLite usam LIMIT 10 no final; o SQL Server usa SELECT TOP 10. Evite SELECT * em código de aplicação: liste as colunas que você realmente precisa.
JOIN: juntando tabelas
Os pedidos só têm o número do cliente. Para mostrar o nome, você junta as duas tabelas pela coluna que as relaciona:
SELECT p.id, c.nome, p.data_pedido, p.valor
FROM pedidos p
INNER JOIN clientes c ON c.id = p.cliente_id
WHERE p.status = 'PAGO';
As letras p e c são apelidos (aliases) que encurtam a escrita. Os dois tipos de JOIN mais usados:
| Tipo | O que retorna | Exemplo de uso |
|---|---|---|
| INNER JOIN | Só as linhas que têm correspondência nas duas tabelas | Pedidos com o nome do cliente |
| LEFT JOIN | Todas as linhas da tabela da esquerda, com NULL onde não houver correspondência | Todos os clientes, inclusive os que nunca compraram |
Um truque útil com LEFT JOIN: encontrar clientes sem nenhum pedido.
SELECT c.id, c.nome
FROM clientes c
LEFT JOIN pedidos p ON p.cliente_id = c.id
WHERE p.id IS NULL;
GROUP BY e funções de agregação
Quando a pergunta é "quanto", "quantos" ou "qual a média", você agrupa linhas e aplica uma função: COUNT, SUM, AVG, MIN e MAX.
-- Total gasto e quantidade de pedidos por cliente
SELECT c.nome,
COUNT(p.id) AS qtd_pedidos,
SUM(p.valor) AS total_gasto
FROM clientes c
INNER JOIN pedidos p ON p.cliente_id = c.id
WHERE p.status = 'PAGO'
GROUP BY c.nome
HAVING SUM(p.valor) > 500
ORDER BY total_gasto DESC;
Duas regras que confundem no começo:
- Toda coluna no SELECT que não está dentro de uma função de agregação precisa estar no GROUP BY. O PostgreSQL e o SQL Server dão erro se você esquecer; o MySQL pode aceitar dependendo da configuração e devolver um valor arbitrário, o que é pior.
- WHERE filtra linhas antes de agrupar; HAVING filtra os grupos depois. No exemplo, o WHERE descarta pedidos não pagos e o HAVING mostra só clientes que passaram de 500 reais.
Em um sistema real, agrupar pelo nome pode juntar dois clientes homônimos. O mais seguro é agrupar por c.id, c.nome.
INSERT, UPDATE e DELETE: alterando dados
Inserir um cliente e um pedido:
INSERT INTO clientes (id, nome, cidade)
VALUES (1, 'Ana Souza', 'Natal');
INSERT INTO pedidos (id, cliente_id, data_pedido, valor, status)
VALUES (10, 1, '2026-10-05', 189.90, 'PENDENTE');
Na prática, o id costuma ser gerado pelo banco (SERIAL ou GENERATED ... AS IDENTITY no PostgreSQL, AUTO_INCREMENT no MySQL, IDENTITY no SQL Server), e você não o informa no INSERT.
Atualizar o status de um pedido:
UPDATE pedidos
SET status = 'PAGO'
WHERE id = 10;
Excluir um pedido:
DELETE FROM pedidos
WHERE id = 10;
Repare que UPDATE e DELETE sempre vêm com WHERE. Sem ele, o comando vale para todas as linhas da tabela.
Cuidados para não apagar dados por engano
Quase todo mundo que trabalha com banco tem uma história de UPDATE sem WHERE. Estes hábitos evitam que a história seja sua:
- Escreva o SELECT primeiro. Antes de um UPDATE ou DELETE, rode
SELECT COUNT(*) FROM pedidos WHERE ...com o mesmo filtro e confira se a quantidade de linhas faz sentido. - Use transação. Abra com
BEGIN(ouSTART TRANSACTIONno MySQL,BEGIN TRANSACTIONno SQL Server), rode o comando, confira o número de linhas afetadas e só então façaCOMMIT. Se algo estiver errado,ROLLBACKdesfaz. - Desconfie do autocommit. Muitas ferramentas gráficas confirmam cada comando automaticamente. Saiba como a sua está configurada.
- Não trabalhe direto em produção. Teste em uma cópia ou em ambiente de desenvolvimento. Em produção, use um usuário com permissões limitadas.
- Tenha backup testado. Backup que nunca foi restaurado não é garantia. Combine com sua equipe ou com quem administra o servidor uma rotina de backups e de testes de restauração.
Se o banco guarda dados pessoais de clientes, lembre também das obrigações da LGPD para pequenas empresas: quem tem acesso, para quê e por quanto tempo.
Próximos passos
Depois do básico, os temas que mais fazem diferença são índices e leitura do plano de execução, que explicam por que uma consulta demora segundos ou milissegundos. O artigo sobre consultas lentas no MySQL e PostgreSQL é um bom ponto de partida. Se você está aprendendo backend, o passo seguinte é conectar o banco a uma aplicação, como na primeira API com Spring Boot, e ver como uma API serve esses dados, assunto do artigo o que é uma API REST.
Sites e sistemas sob medida
Controle de pedidos, cadastro de clientes e relatórios saem bem melhores quando o banco de dados é bem modelado desde o início. A PruPru desenvolve sistemas web para pequenas empresas com esse cuidado.
Ver serviços →Perguntas frequentes
Qual banco de dados é melhor para aprender SQL?
Qualquer um dos grandes serve, porque o SQL básico é praticamente igual em todos. PostgreSQL é uma ótima escolha por ser gratuito, muito usado no mercado e seguir o padrão de perto. SQLite é o mais simples para testes rápidos.
Qual a diferença entre WHERE e HAVING?
WHERE filtra as linhas antes do agrupamento e não pode usar funções de agregação. HAVING filtra os grupos depois do GROUP BY e é onde você coloca condições como SUM maior que um valor.
Dá para desfazer um DELETE?
Só se o comando foi executado dentro de uma transação ainda não confirmada, caso em que o ROLLBACK desfaz. Depois do COMMIT, a saída é restaurar um backup, por isso o hábito de conferir com SELECT antes é tão importante.
SQL é uma linguagem de programação?
SQL é uma linguagem de consulta declarativa: você descreve o resultado que quer e o banco decide como buscar. Ela é usada junto com linguagens como Java, Python ou JavaScript, que cuidam da lógica da aplicação.