Aprenda Bases de dados e SQL do zero
1O que é um banco de dados relacional
Um banco de dados relacional guarda dados em tabelas. Uma tabela parece uma planilha: cada linha é um registro, cada coluna é uma propriedade.
Uma loja pode ter uma tabela customers com as colunas id, name e city, e uma tabela orders com as colunas id, customer_id e total.
Uma chave primária é uma coluna, ou um conjunto de colunas, que identifica cada linha de forma única. Ela nunca pode se repetir nem ficar vazia. Aqui é o id de cada tabela.
Uma chave estrangeira é uma coluna que se refere à chave primária de outra tabela. Em orders, customer_id diz qual cliente fez o pedido.
É assim que as tabelas são ligadas: um cliente pode ter muitos pedidos, mas cada pedido pertence a um cliente. Isso é um relacionamento um-para-muitos.
SQL (Structured Query Language) é a linguagem usada para criar tabelas, alterar dados e fazer perguntas sobre eles.
Autoavaliação O que é uma chave primária?
- A primeira coluna de toda tabela
- Um índice que torna as buscas mais rápidas
- Uma coluna ou conjunto de colunas que identifica cada linha de forma única
- Uma coluna que se refere a uma linha de outra tabela
Resposta: Uma coluna ou conjunto de colunas que identifica cada linha de forma única. Uma chave primária é única e nunca é NULL, então identifica exatamente uma linha. Uma coluna que se refere a outra tabela é uma chave estrangeira.
2Lendo dados com SELECT
A maioria das questões trata do comando SELECT. Ele é construído com cláusulas, sempre escritas nesta ordem:
SELECT … FROM … WHERE … GROUP BY … HAVING … ORDER BY …
- SELECT lista as colunas desejadas. DISTINCT remove linhas duplicadas.
- FROM nomeia a tabela, ou as tabelas unidas.
- WHERE mantém apenas as linhas que atendem a uma condição, por exemplo WHERE total > 20.
- GROUP BY coloca linhas com o mesmo valor num grupo, para que você possa contar ou somar por grupo.
- HAVING mantém apenas os grupos que atendem a uma condição. Pode usar agregações, o que o WHERE não pode.
- ORDER BY ordena o resultado, em ordem crescente por padrão; acrescente DESC para o maior primeiro.
As funções de agregação resumem muitas linhas em um valor: COUNT, SUM, AVG, MIN e MAX.
O banco de dados não executa as cláusulas na ordem em que você as escreve. Ele executa primeiro FROM, depois WHERE, GROUP BY, HAVING, SELECT e por fim ORDER BY.
Outros comandos alteram dados: INSERT adiciona linhas, UPDATE altera linhas e DELETE remove linhas. CREATE, ALTER e DROP alteram as próprias tabelas.
Autoavaliação Você quer apenas os clientes com mais de 5 pedidos. Qual cláusula filtra por COUNT(*) > 5?
- DISTINCT
- HAVING
- ORDER BY
- WHERE
Resposta: HAVING. A contagem só existe depois de as linhas serem agrupadas, e o HAVING filtra grupos. O WHERE é executado antes do agrupamento, então não pode usar uma agregação como COUNT.
3Junções, normalização e transações
Uma junção (join) combina linhas de duas tabelas usando uma condição, geralmente chave estrangeira = chave primária:
FROM customers c JOIN orders o ON o.customer_id = c.id
- INNER JOIN (ou JOIN) mantém apenas as linhas que têm correspondência nas duas tabelas.
- LEFT JOIN mantém todas as linhas da tabela da esquerda. Onde não há correspondência, as colunas da tabela da direita ficam NULL.
- NULL significa que um valor está ausente ou é desconhecido. Teste-o com IS NULL, nunca com = NULL.
A normalização divide as tabelas para que cada fato seja guardado uma só vez. Isso evita atualizar o mesmo fato em vários lugares.
- 1FN: cada célula contém um único valor atômico, sem grupos repetidos.
- 2FN: 1FN, e toda coluna que não é chave depende da chave inteira, não de parte de uma chave composta.
- 3FN: 2FN, e nenhuma coluna que não é chave depende de outra coluna que não é chave.
Uma transação agrupa comandos em uma unidade. COMMIT a torna permanente e ROLLBACK a desfaz. As transações seguem o ACID: atomicidade (tudo ou nada), consistência, isolamento e durabilidade.
Autoavaliação Um cliente não fez nenhum pedido. O que acontece com esse cliente em customers LEFT JOIN orders?
- A consulta falha com um erro
- O cliente aparece uma vez para cada pedido da tabela
- O cliente aparece uma vez, com NULL nas colunas do pedido
- O cliente fica de fora do resultado
Resposta: O cliente aparece uma vez, com NULL nas colunas do pedido. Um LEFT JOIN mantém todas as linhas da tabela da esquerda e preenche o lado direito ausente com NULL. Deixar o cliente de fora é o que faz um INNER JOIN.
4O método passo a passo
Para escrever uma consulta, ou descobrir o que uma consulta dada devolve:
- Encontre as tabelas que guardam os dados e como elas se ligam por chaves.
- Escreva o FROM com as junções. Escolha LEFT JOIN quando as linhas sem correspondência devem permanecer.
- Acrescente WHERE para condições sobre linhas individuais.
- Se a questão diz “por” ou “para cada”, acrescente GROUP BY e a agregação.
- Acrescente HAVING para condições sobre a agregação e depois ORDER BY se a ordem importar.
- Confira o resultado num exemplo pequeno: liste as linhas depois de cada cláusula, na ordem em que o banco de dados as executa.
Para uma questão teórica, nomeie primeiro o conceito (uma chave, um tipo de junção, uma forma normal, uma propriedade ACID) e depois escolha a opção que corresponde à sua definição.
5Um exemplo resolvido
Acompanhe cada passo. Tente prever o próximo antes de abri-lo.
Exemplo resolvidoA tabela customers tem as linhas (1, Ana), (2, Ben) e (3, Cas). A tabela orders tem as linhas (id, customer_id) = (10, 1), (11, 1), (12, 2) e (13, 1). O que esta consulta devolve? SELECT c.name, COUNT(o.id) FROM customers c LEFT JOIN orders o ON o.customer_id = c.id GROUP BY c.name
1Cada cliente é pareado com os pedidos que levam o seu id. Ana corresponde aos pedidos 10, 11 e 13. Ben corresponde ao pedido 12.
Cas não tem pedidos. Como é um LEFT JOIN, Cas permanece no resultado, com NULL em o.id.
2- Ana, 10
- Ana, 11
- Ana, 13
- Ben, 12
- Cas, NULL
São 5 linhas.
3GROUP BY c.name forma três grupos: Ana com 3 linhas, Ben com 1 linha e Cas com 1 linha.
4COUNT(o.id) conta apenas os valores que não são NULL. Ana recebe 3 e Ben recebe 1.
Cas tem uma linha, mas o seu o.id é NULL, então Cas recebe 0.
5Ana, Ben e Cas juntos têm 3 + 1 + 0 = 4 pedidos, o mesmo que o número de linhas de orders. Com COUNT(*) no lugar, Cas receberia 1 por engano, porque COUNT(*) conta a própria linha.
Resposta Ana 3, Ben 1, Cas 0.
6Erros comuns
- Usar uma agregação no WHERE. Condições sobre COUNT, SUM ou AVG pertencem ao HAVING.
- Escrever = NULL. Qualquer comparação com NULL é desconhecida; use IS NULL ou IS NOT NULL.
- Usar um INNER JOIN quando as linhas sem correspondência devem permanecer. Use um LEFT JOIN.
- Esquecer a condição da junção. Sem ON, cada linha é pareada com todas as linhas (um produto cartesiano, ou cross join).
- Selecionar uma coluna que não está no GROUP BY nem dentro de uma agregação.
- Confundir DELETE (remove linhas) com DROP TABLE (remove a tabela inteira).
- Executar UPDATE ou DELETE sem WHERE. Ele altera todas as linhas da tabela.
Autoavaliação Uma tabela tem 10 linhas, e a coluna col é NULL em todas elas. O que SELECT COUNT(col) devolve?
- 0
- 10
- 1
- NULL
Resposta: 0. COUNT(col) conta apenas os valores que não são NULL, então devolve 0. COUNT(*) conta linhas e devolveria 10.
7Como são as questões de prova
- Fácil: termos e fatos essenciais. O que SELECT, WHERE, ORDER BY ou DELETE fazem, chaves primárias e estrangeiras, o que NULL significa.
- Médio: aplicação dos conceitos. A consulta certa para uma tarefa, WHERE versus HAVING, junções internas versus externas, as formas normais, ACID.
- Difícil: casos e análise. Subconsultas, níveis de isolamento e suas anomalias, BCNF, funções de janela, índices e desempenho de consultas, injeção de SQL.
Quando uma consulta for dada, simule-a em algumas linhas na ordem FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY. A maioria das armadilhas aparece em três linhas.
Aprenda passo a passo no aplicativoAprenda passo a passo no aplicativo