# 📘 SQL para Concursos — Banca FCC
> Resumo completo com foco nas questões da FCC: ordem de execução, cláusulas, funções, joins, subqueries e pegadinhas clássicas.
---
## 1. ESTRUTURA GERAL DE UMA QUERY SELECT
```sql
SELECT [colunas / expressões / funções de agregação]
FROM [tabela(s)]
JOIN [tabela] ON [condição]
WHERE [filtro de linhas]
GROUP BY [colunas de agrupamento]
HAVING [filtro sobre grupos]
ORDER BY [colunas de ordenação]
LIMIT [quantidade de linhas] -- nem sempre cobrado
```
---
## 2. ORDEM DE EXECUÇÃO (LÓGICA) ⚠️ CUIDADO NAS PROVAS
A FCC cobra bastante a **ordem em que o banco de dados processa** as cláusulas — que é **diferente** da ordem em que escrevemos.
| Passo | Cláusula | O que faz |
|-------|----------------|----------------------------------------------|
| 1 | `FROM` | Define as tabelas (e produto cartesiano) |
| 2 | `JOIN` | Aplica os joins |
| 3 | `WHERE` | Filtra as linhas (antes do agrupamento) |
| 4 | `GROUP BY` | Agrupa as linhas |
| 5 | `HAVING` | Filtra os grupos (depois do agrupamento) |
| 6 | `SELECT` | Seleciona / calcula as colunas |
| 7 | `DISTINCT` | Remove duplicatas |
| 8 | `ORDER BY` | Ordena o resultado |
| 9 | `LIMIT/OFFSET` | Limita a quantidade de linhas retornadas |

> **Pegadinha clássica FCC:** `WHERE` **não pode usar** alias definidos no `SELECT` nem funções de agregação (`SUM`, `COUNT`, etc.), pois o `WHERE` é executado **antes** do `SELECT`. Use `HAVING` para filtrar agregações.
---
## 3. DIFERENÇA ENTRE WHERE e HAVING
| Característica | WHERE | HAVING |
|------------------------|------------------------------|-------------------------------|
| Momento de execução | Antes do GROUP BY | Depois do GROUP BY |
| Filtra | Linhas individuais | Grupos |
| Pode usar agregação? | ❌ Não | ✅ Sim |
| Pode usar sem GROUP BY?| ✅ Sim | ✅ Sim (filtra resultado total)|
```sql
-- ✅ CORRETO
SELECT departamento, COUNT(*) AS total
FROM funcionarios
WHERE salario > 1000 -- filtra linhas antes de agrupar
GROUP BY departamento
HAVING COUNT(*) > 5; -- filtra grupos após agrupar
-- ❌ ERRADO — FCC adora essa pegadinha!
SELECT departamento, COUNT(*) AS total
FROM funcionarios
WHERE COUNT(*) > 5 -- ERRO: não pode usar agregação no WHERE
GROUP BY departamento;
```
---
## 4. FUNÇÕES DE AGREGAÇÃO
| Função | Descrição |
|---------------|------------------------------------------------|
| `COUNT(*)` | Conta todas as linhas (incluindo NULLs) |
| `COUNT(col)` | Conta linhas onde col **não é NULL** |
| `SUM(col)` | Soma os valores (ignora NULL) |
| `AVG(col)` | Média dos valores (ignora NULL) |
| `MAX(col)` | Maior valor |
| `MIN(col)` | Menor valor |
> **Atenção:** `COUNT(*)` ≠ `COUNT(coluna)`. Se a coluna tiver NULLs, `COUNT(coluna)` retornará menos.
---
## 5. TIPOS DE JOIN
```
Tabela A Tabela B
[ A ∩ B ]
```
| JOIN | Retorna |
|-----------------|------------------------------------------------------------|
| `INNER JOIN` | Apenas linhas com correspondência em **ambas** as tabelas |
| `LEFT JOIN` | Todas de A + correspondências de B (B sem match = NULL) |
| `RIGHT JOIN` | Todas de B + correspondências de A (A sem match = NULL) |
| `FULL OUTER JOIN`| Todas de A e B (sem match = NULL em qualquer lado) |
| `CROSS JOIN` | Produto cartesiano (todas as combinações) |
| `SELF JOIN` | Join da tabela com ela mesma (usa alias) |
```sql
-- INNER JOIN
SELECT e.nome, d.nome AS departamento
FROM empregado e
INNER JOIN departamento d ON e.dep_id = d.id;
-- LEFT JOIN — inclui empregados SEM departamento
SELECT e.nome, d.nome AS departamento
FROM empregado e
LEFT JOIN departamento d ON e.dep_id = d.id;
-- SELF JOIN — encontrar funcionário e seu gerente
SELECT e.nome AS funcionario, g.nome AS gerente
FROM funcionario e
JOIN funcionario g ON e.gerente_id = g.id;
```

> **FCC cobra:** qual join retorna linhas sem correspondência e de qual lado.
---
## 6. SUBQUERIES (SUBCONSULTAS)
### 6.1 No WHERE
```sql
-- Funcionários que ganham mais que a média
SELECT nome FROM funcionario
WHERE salario > (SELECT AVG(salario) FROM funcionario);
```
### 6.2 Correlacionadas
A subquery referencia a query externa — executada **uma vez por linha** da query principal.
```sql
SELECT nome FROM funcionario f
WHERE salario > (
SELECT AVG(salario) FROM funcionario
WHERE departamento_id = f.departamento_id
);
```
### 6.3 EXISTS / NOT EXISTS
```sql
-- Departamentos que têm pelo menos 1 funcionário
SELECT nome FROM departamento d
WHERE EXISTS (
SELECT 1 FROM funcionario WHERE departamento_id = d.id
);
```
### 6.4 IN / NOT IN
```sql
SELECT nome FROM funcionario
WHERE departamento_id IN (SELECT id FROM departamento WHERE cidade = 'SP');
```
> **Pegadinha FCC com NOT IN e NULL:** Se a subquery retornar algum NULL, `NOT IN` retorna **vazio**! Use `NOT EXISTS` para segurança.
---
## 7. OPERADORES DE CONJUNTO
| Operador | Descrição |
|---------------|-------------------------------------------------------------|
| `UNION` | Une resultados, **remove duplicatas** |
| `UNION ALL` | Une resultados, **mantém duplicatas** (mais rápido) |
| `INTERSECT` | Retorna apenas linhas presentes nas **duas** consultas |
| `EXCEPT` | Retorna linhas da 1ª consulta que **não estão** na 2ª |
> **Regras obrigatórias:** Mesmo número de colunas e tipos compatíveis em cada posição.
---
## 8. FUNÇÕES DE STRING (mais cobradas pela FCC)
| Função | Descrição | Exemplo |
|--------------------------------|----------------------------------------|------------------------------------|
| `UPPER(str)` | Converte para maiúsculas | `UPPER('sql')` → `'SQL'` |
| `LOWER(str)` | Converte para minúsculas | `LOWER('SQL')` → `'sql'` |
| `LENGTH(str)` / `LEN(str)` | Comprimento da string | `LENGTH('abc')` → `3` |
| `SUBSTRING(str, pos, len)` | Extrai parte da string | `SUBSTRING('abcde', 2, 3)` → `'bcd'`|
| `TRIM(str)` | Remove espaços dos dois lados | `TRIM(' x ')` → `'x'` |
| `LTRIM` / `RTRIM` | Remove espaços da esquerda/direita | |
| `CONCAT(a, b)` | Concatena strings | `CONCAT('a','b')` → `'ab'` |
| `REPLACE(str, old, new)` | Substitui substring | |
| `LIKE` | Comparação com padrão | `LIKE 'A%'` (começa com A) |
**Wildcards do LIKE:**
- `%` → qualquer sequência de caracteres (inclusive vazia)
- `_` → exatamente **um** caractere qualquer
---
## 9. FUNÇÕES NUMÉRICAS
| Função | Descrição |
|------------------|----------------------------------|
| `ROUND(n, d)` | Arredonda n com d casas decimais |
| `FLOOR(n)` | Arredonda para baixo |
| `CEILING(n)` | Arredonda para cima |
| `ABS(n)` | Valor absoluto |
| `MOD(a, b)` | Resto da divisão |
| `POWER(a, b)` | a elevado a b |
---
## 10. FUNÇÕES DE DATA
| Função | Descrição |
|-------------------------------|-------------------------------------|
| `CURRENT_DATE` | Data atual |
| `CURRENT_TIMESTAMP` / `NOW()` | Data e hora atual |
| `EXTRACT(parte FROM data)` | Extrai ano, mês, dia, hora... |
| `DATEDIFF(d1, d2)` | Diferença entre datas (dias) |
| `DATE_ADD(data, INTERVAL n)` | Adiciona intervalo à data |
```sql
SELECT EXTRACT(YEAR FROM data_admissao) AS ano FROM funcionario;
```
---
## 11. NULL — COMPORTAMENTO ESPECIAL ⚠️
- Qualquer operação aritmética com NULL resulta em **NULL**
- Qualquer comparação com NULL resulta em **NULL** (não TRUE, não FALSE)
- Use `IS NULL` e `IS NOT NULL` para verificar
- `NULL = NULL` → **FALSE** (ou NULL, dependendo do contexto)
- `COALESCE(a, b, c)` → retorna o **primeiro valor não-NULL**
- `NULLIF(a, b)` → retorna NULL se a = b, senão retorna a
```sql
-- ❌ ERRADO
WHERE salario = NULL
-- ✅ CORRETO
WHERE salario IS NULL
-- COALESCE
SELECT COALESCE(comissao, 0) FROM funcionario; -- substitui NULL por 0
```
---
## 12. DDL — COMANDOS DE DEFINIÇÃO
| Comando | Descrição |
|------------------|------------------------------------|
| `CREATE TABLE` | Cria tabela |
| `ALTER TABLE` | Altera estrutura da tabela |
| `DROP TABLE` | Remove tabela e seus dados |
| `TRUNCATE TABLE` | Remove **todos os dados** da tabela (mais rápido que DELETE sem WHERE) |
| `CREATE INDEX` | Cria índice |
| `CREATE VIEW` | Cria visão |
```sql
CREATE TABLE produto (
id INT PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
preco DECIMAL(10,2),
cat_id INT REFERENCES categoria(id) -- FK
);
ALTER TABLE produto ADD COLUMN estoque INT DEFAULT 0;
ALTER TABLE produto DROP COLUMN estoque;
```
---
## 13. DML — COMANDOS DE MANIPULAÇÃO
```sql
-- INSERT
INSERT INTO produto (id, nome, preco) VALUES (1, 'Caneta', 2.50);
-- UPDATE
UPDATE produto SET preco = 3.00 WHERE id = 1;
-- DELETE
DELETE FROM produto WHERE id = 1;
-- TRUNCATE (sem WHERE, não pode ter rollback em alguns SGBDs)
TRUNCATE TABLE produto;
```
> **Diferença DELETE vs TRUNCATE:**
> - `DELETE` pode ter `WHERE`, pode fazer rollback, dispara triggers
> - `TRUNCATE` remove tudo, geralmente mais rápido, pode não disparar triggers
---
## 14. DCL — CONTROLE DE ACESSO
```sql
GRANT SELECT, INSERT ON produto TO usuario1;
REVOKE INSERT ON produto FROM usuario1;
```
---
## 15. TCL — CONTROLE DE TRANSAÇÕES
```sql
BEGIN; -- inicia transação
COMMIT; -- confirma alterações
ROLLBACK; -- desfaz alterações
SAVEPOINT sp1; -- cria ponto de salvamento
ROLLBACK TO sp1; -- volta ao savepoint
```
### Propriedades ACID
| Propriedade | Descrição |
|---------------|------------------------------------------------------------|
| **A**tomicity | A transação é tudo ou nada |
| **C**onsistency | O banco vai de um estado válido para outro válido |
| **I**solation | Transações concorrentes não interferem entre si |
| **D**urability | Após COMMIT, as mudanças persistem mesmo com falha |
---
## 16. CONSTRAINTS (RESTRIÇÕES)
| Constraint | Descrição |
|-----------------|------------------------------------------------------|
| `PRIMARY KEY` | Identifica unicamente cada linha (NOT NULL + UNIQUE) |
| `FOREIGN KEY` | Referencia PK de outra tabela |
| `UNIQUE` | Valores únicos (permite NULL, depende do SGBD) |
| `NOT NULL` | Não permite valor nulo |
| `CHECK` | Valida condição |
| `DEFAULT` | Valor padrão quando não informado |
---
## 17. VIEWS (VISÕES)
```sql
CREATE VIEW vw_funcionarios_sp AS
SELECT nome, salario FROM funcionario WHERE cidade = 'SP';
-- Consultar a view como se fosse tabela
SELECT * FROM vw_funcionarios_sp;
DROP VIEW vw_funcionarios_sp;
```
> **FCC cobra:** Views são consultas armazenadas, **não armazenam dados físicos** (exceto materialized views). Simplificam consultas complexas e podem restringir acesso.
---
## 18. ÍNDICES
```sql
CREATE INDEX idx_func_nome ON funcionario(nome);
CREATE UNIQUE INDEX idx_func_cpf ON funcionario(cpf);
DROP INDEX idx_func_nome;
```
> Índices **aceleram leituras** (`SELECT`) mas **penalizam escritas** (`INSERT`, `UPDATE`, `DELETE`). A PRIMARY KEY cria índice automaticamente.
---
## 19. DISTINCT e GROUP BY — DIFERENÇAS
```sql
-- DISTINCT: remove linhas duplicadas no resultado final
SELECT DISTINCT departamento FROM funcionario;
-- GROUP BY: agrupa para usar funções de agregação
SELECT departamento, COUNT(*) FROM funcionario GROUP BY departamento;
```
> `GROUP BY` sem função de agregação se comporta de forma semelhante ao `DISTINCT`, mas são conceitualmente diferentes.
---
## 20. ORDER BY
```sql
SELECT nome, salario FROM funcionario
ORDER BY salario DESC, nome ASC;
-- Pode usar número da coluna (FCC adora cobrar isso)
ORDER BY 2 DESC, 1 ASC; -- equivalente ao anterior
```
- `ASC` → crescente (padrão, pode omitir)
- `DESC` → decrescente
- NULL: comportamento varia por SGBD (geralmente vai para o final no ASC)
---
## 21. CASE WHEN
```sql
SELECT nome,
CASE
WHEN salario < 2000 THEN 'Baixo'
WHEN salario < 5000 THEN 'Médio'
ELSE 'Alto'
END AS faixa_salarial
FROM funcionario;
```
---
## 22. PEGADINHAS CLÁSSICAS DA FCC ⚠️
1. **`WHERE` com agregação** → ERRO. Use `HAVING`.
2. **`NOT IN` com NULL na subquery** → retorna zero linhas.
3. **`COUNT(*)` vs `COUNT(coluna)`** → NULL é ignorado no segundo.
4. **Alias do SELECT não pode ser usado no WHERE** (mas pode no ORDER BY em alguns SGBDs).
5. **`UNION` remove duplicatas, `UNION ALL` não** → impacto na performance.
6. **`DELETE` sem WHERE** apaga tudo mas é diferente de `TRUNCATE`.
7. **`NULL = NULL` é FALSE** → sempre use `IS NULL`.
8. **`BETWEEN a AND b`** → inclusivo nos dois extremos.
9. **`LIKE '%texto%'`** → não usa índice, lento em tabelas grandes.
10. **Produto cartesiano sem JOIN condition** → `FROM A, B` sem WHERE gera todas as combinações.
---
## 23. EXEMPLOS DE QUESTÕES FCC — PADRÃO
### Questão tipo: "Qual o resultado da query?"
```sql
SELECT d.nome, COUNT(f.id) AS qtd
FROM departamento d
LEFT JOIN funcionario f ON f.dep_id = d.id
GROUP BY d.nome
HAVING COUNT(f.id) >= 2
ORDER BY qtd DESC;
```
> Retorna departamentos com **2 ou mais** funcionários, ordenados do maior para o menor. Departamentos sem funcionários **não** aparecem (por causa do HAVING filtrando COUNT = 0).
---
### Questão tipo: "Qual cláusula está incorreta?"
```sql
SELECT departamento, AVG(salario)
FROM funcionario
WHERE AVG(salario) > 3000 -- ❌ ERRADO
GROUP BY departamento;
```
> Deve substituir `WHERE` por `HAVING`.
---
*Resumo elaborado com foco nas cobranças recorrentes da banca FCC em concursos públicos de TI e áreas afins.*
**EXTRA**
Trabalhando com datas em 3 diferentes bancos de dado.

Sintaxe do