SQL do zero em poucos minutos

Os comandos básicos de SQL para consultar, inserir, atualizar e deletar dados direto no banco, sem depender de um ORM para entender o que está acontecendo por trás dele.


Faz um tempo surgiu o jQuery, uma biblioteca de JavaScript que trouxe muita produtividade para quem programava na época. O problema é que ela criou uma leva de gente que só sabia usar jQuery. Precisava fazer um botão funcionar e não sabia escrever aquilo em JavaScript puro, tinha que importar a biblioteca inteira para resolver algo simples.

Algo parecido acontece hoje com banco de dados. Existem os ORMs, bibliotecas disponíveis para praticamente qualquer linguagem que funcionam como um intermediário na manipulação do banco. Você dá um comando simples e por baixo dos panos o ORM monta toda a consulta, seja para inserir, remover, atualizar ou buscar um dado. Isso é ótimo para produtividade, mas também gera uma quantidade grande de gente que nunca aprendeu a escrever um comando direto no banco. Por isso vale entender o básico de SQL, mesmo que no dia a dia você vá trabalhar com um ORM por cima disso.

A base para testar os comandos

Para acompanhar não é preciso instalar banco de dados nenhum na máquina. Existem ferramentas visuais, como o DBeaver, que permitem enxergar o que tem dentro do banco e rodar comandos direto por ali, sem precisar montar um sistema completo só para testar uma consulta.

Como exemplo vou usar duas tabelas simples: uma de clientes, com id, nome, e-mail, telefone, cidade e data de registro, e uma de pedidos, associada aos clientes, com id, data, valor e status. Tudo que vem a seguir vale para qualquer banco relacional, com pequenas variações de sintaxe. PostgreSQL, MySQL e MariaDB seguem basicamente a mesma lógica.

Selecionando dados

Dar um comando ao banco é como montar uma frase. Para pegar a lista de clientes, o comando é:

SELECT * FROM clientes;

Select significa selecione, o asterisco indica todos os campos, e from clientes indica de qual tabela. O ponto e vírgula marca o fim do comando.

O asterisco pode ser trocado pelos campos específicos que interessam. Se só é preciso o id e o nome do cliente, não faz sentido trazer telefone, e-mail, cidade e data de registro junto:

SELECT cliente_id, nome FROM clientes;

Em um sistema pequeno, com poucos registros, isso não faz diferença nenhuma de performance. Mas quando o volume cresce, cada campo desnecessário é processamento e tráfego extra sendo carregado à toa. Com 5 registros uma consulta completa leva os mesmos milissegundos que uma consulta filtrada. Com 1 milhão de registros e milhares de acessos simultâneos, a diferença começa a pesar. Pegar só o que é necessário é um hábito que vale criar desde cedo.

Filtrando com WHERE

Para filtrar resultados entra o WHERE, que significa onde. Por exemplo, todos os clientes que moram em São Paulo:

SELECT * FROM clientes WHERE cidade = 'São Paulo';

Ou pedidos com status concluído:

SELECT * FROM pedidos WHERE status = 'concluido';

Dá para combinar mais de uma condição com AND. Pedidos concluídos com valor acima de 150:

SELECT * FROM pedidos WHERE status = 'concluido' AND valor_total > 150;

Um detalhe que costuma confundir quem já programa: em SQL a comparação usa um único sinal de igual, não dois. Não é uma atribuição de valor, é uma pergunta, tipo "o status é igual a concluído?".

Ordenando com ORDER BY

Depois de filtrar, dá para ordenar o resultado com ORDER BY, indicando o campo e se a ordem é ascendente (ASC, do menor para o maior) ou descendente (DESC, do maior para o menor):

SELECT * FROM pedidos WHERE status = 'concluido' ORDER BY valor_total DESC;

Isso é a base de qualquer ranking. Se a ideia é mostrar os pedidos mais caros primeiro, ou os usuários com mais pontuação no topo, o caminho é sempre ordenar decrescente pelo campo relevante.

Vale mencionar que existe ainda o conceito de join, que relaciona duas tabelas na mesma consulta, por exemplo para trazer o nome do cliente junto do pedido em vez de só o id dele. É um assunto um pouco mais avançado que fica para outro momento.

Inserindo dados com INSERT

Para adicionar um registro novo, o comando muda de select para insert:

INSERT INTO clientes (nome, email, telefone, cidade)
VALUES ('Fulano', 'fulano@hotmail.com', '99999-9999', 'São Paulo');

Entre parênteses depois do nome da tabela ficam os campos que serão preenchidos, e depois do VALUES os valores correspondentes, na mesma ordem. Textos ficam entre aspas, números não precisam. O id costuma ser gerado automaticamente pelo banco, sem precisar informar.

Atualizando dados com UPDATE

Para atualizar um registro existe o comando update, que precisa de duas coisas: o que vai mudar e como identificar exatamente qual registro:

UPDATE clientes
SET nome = 'Fulano de Tal'
WHERE cliente_id = 6;

O SET define o novo valor, e o WHERE restringe a alteração a um registro específico. Sem o where, o update afeta todas as linhas da tabela, o que quase nunca é a intenção. Por isso o ideal é sempre filtrar por algo único, como o id ou um e-mail, para ter certeza de que só aquele registro vai ser alterado.

Deletando dados com DELETE

O delete é o comando mais simples e também o mais perigoso, porque não tem volta. Não existe lixeira em banco de dados:

DELETE FROM clientes WHERE email = 'fulano@hotmail.com';

Assim como no update, o where aqui é essencial. Sem ele, o comando apaga a tabela inteira. Existem formas de reverter operações usando transações, mas isso já é um assunto mais avançado.

O CRUD por trás de tudo

Select, insert, update e delete formam o que se chama de CRUD, as quatro operações básicas de manipulação de dados: criar, ler, atualizar e deletar. É o básico do básico, mas é importante saber mesmo usando um ORM, porque é exatamente isso que ele está montando por baixo dos panos quando você chama um método como create ou findMany.

Entender como fazer essas consultas na mão ajuda a usar qualquer ORM de forma mais consciente, inclusive a perceber quando uma consulta está gerando mais processamento do que deveria, como no caso de subqueries mal pensadas, que são uma consulta dentro da outra e podem custar caro em performance dependendo de como são montadas.

Esses comandos são a base de praticamente todo sistema que lida com dado persistente. Uma vez que eles fazem sentido, o resto, joins, subqueries, índices, vai se encaixando em cima dessa fundação.