Específicos · Bancos de Dados
SQL: DDL/DML/DQL/DCL/TCL, WHERE × HAVING, joins, NULL, subconsultas, views, janela
Leia a consulta na ordem em que ela é avaliada — FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY — e leia o verbo para saber a sublinguagem. Quase todo item cai nessas duas leituras.
Média145 itens no tópico
A ideia que organiza o assunto
SQL é declarativa: você descreve o resultado desejado, não o caminho para obtê-lo. Mas a linguagem tem uma ordem lógica de avaliação fixa, e é ela que resolve a prova. Cada cláusula recebe o que a anterior produziu:
FROM -- forma as combinações de linhas (produto cartesiano, depois junções)
WHERE -- filtra LINHAS, antes de qualquer agregação
GROUP BY -- reúne as linhas sobreviventes em grupos
HAVING -- filtra GRUPOS, depois da agregação
SELECT -- projeta as colunas (e é aqui que o DISTINCT age)
ORDER BY -- ordena o que sobrou
Quase tudo o que a banca cobra é consequência direta desse encadeamento. O
produto cartesiano existe porque o FROM combina tudo e só o WHERE (ou o ON)
reduz. WHERE não enxerga SUM porque a agregação ainda não aconteceu; HAVING
enxerga porque já aconteceu. Sem ORDER BY não há ordem nenhuma, porque a última
etapa não foi pedida. E o número de linhas de uma consulta agrupada é o número de
valores distintos das colunas do GROUP BY — não o número de linhas da tabela.
A segunda metade da ideia é mais simples ainda: a sublinguagem se lê no
verbo, não no objeto. CREATE VIEW é DDL mesmo que a view seja feita de um
SELECT; UPDATE é DML mesmo que o item fale em “definição de coluna”.
Diante de um item deste assunto, faça as duas leituras nesta ordem: qual é o verbo e em que etapa do encadeamento aquilo aconteceria. Uma das duas decide a esmagadora maioria dos itens.
Como funciona
As sublinguagens. A divisão que a CEBRASPE usa tem cinco partes, mas ela nem sempre emprega as cinco no mesmo caderno — e isso importa (ver adiante).
| sigla | comandos | o que toca |
|---|---|---|
| DDL | CREATE, ALTER, DROP, TRUNCATE | a estrutura e o catálogo (metadados) |
| DML | INSERT, UPDATE, DELETE | as linhas |
| DQL | SELECT | nada; só recupera |
| DCL | GRANT, REVOKE | privilégios |
| TCL | COMMIT, ROLLBACK, SAVEPOINT | a transação em curso |
Os três graus de remoção caem sempre juntos e nunca são intercambiáveis:
DELETE FROM alunos WHERE id = 7; -- DML: apaga linhas escolhidas, aceita WHERE
TRUNCATE TABLE alunos; -- DDL: esvazia a tabela, mantém a estrutura
DROP TABLE alunos; -- DDL: elimina a tabela, os dados e os índices
Não existe DELETE TABLE. DELETE é transacional e pode ser desfeito por
ROLLBACK; TRUNCATE e DROP, por serem DDL, normalmente não.
Alterar estrutura é sempre ALTER TABLE, com ADD, DROP COLUMN ou
MODIFY. Nenhum UPDATE muda tipo de coluna, e nenhuma variável nomeia uma
coluna a ser removida.
Junções. O FROM com duas tabelas e nenhuma condição devolve o produto
cartesiano. A condição é que o reduz — escrita no WHERE (estilo antigo) ou no
ON (estilo ANSI), o efeito é o mesmo.
| tipo | preserva |
|---|---|
INNER JOIN | só os pares que casam |
LEFT JOIN | todas as linhas da tabela à esquerda, com NULL à direita |
RIGHT JOIN | todas as da direita |
FULL JOIN | as duas |
CROSS JOIN | o produto cartesiano, explicitamente |
Em cadeia de junções, basta um INNER JOIN depois de um LEFT JOIN para
anular a preservação obtida antes: as linhas estendidas com NULL não casam com
nada e são descartadas.
A antijunção é o idioma que a banca mais exibe, e ele tem duas formas:
-- forma 1: junção externa + o filtro que retém os que não casaram
SELECT a.id FROM software a
LEFT OUTER JOIN vsoftware b ON a.id = b.idsoft
WHERE b.idsoft IS NULL;
-- forma 2: subconsulta negada
SELECT a.id FROM software a
WHERE a.id NOT IN (SELECT b.idsoft FROM vsoftware b);
Sem o WHERE ... IS NULL, a forma 1 não é antijunção: ela devolve tudo, com
nulos onde não houve par. E as duas formas só são equivalentes enquanto a
subconsulta da forma 2 não contiver NULL — se contiver, NOT IN não devolve
linha alguma, ao passo que NOT EXISTS e a junção externa continuam corretos.
Operações de conjunto. UNION, INTERSECT e EXCEPT exigem
compatibilidade de união: mesmo número de colunas, tipos compatíveis, na
mesma ordem. Todas eliminam duplicatas; a palavra ALL é o interruptor que as
preserva.
Subconsultas. Podem aparecer no SELECT, no FROM (tabela derivada), no
WHERE e no HAVING, e podem ser aninhadas. A distinção que decide itens é
outra: a subconsulta é correlacionada quando menciona uma coluna da consulta
externa. Se for, é reavaliada linha a linha — daí o custo. Se não for, o
resultado é o mesmo para todas as linhas: um EXISTS não correlacionado ou passa
tudo ou não passa nada.
-- correlacionada: reavaliada por linha de pedidos
DELETE FROM pedidos p
WHERE NOT EXISTS (SELECT 1 FROM vendedores v
WHERE v.codigo_vendedor = p.codigo_vendedor);
Views. A view comum é uma tabela virtual: o SGBD guarda no catálogo o
texto da consulta e a executa a cada acesso. Não ocupa espaço, não armazena
linhas, e por isso está sempre atualizada. A view materializada guarda
fisicamente o resultado já calculado — é mais rápida e, exatamente por isso,
pode estar defasada até o próximo refresh.
NULL. NULL é ausência de valor, não zero nem string vazia. Qualquer
comparação com ele resulta em desconhecido, de modo que = NULL nunca casa e o
teste correto é IS NULL / IS NOT NULL. INNER JOIN nunca casa a linha cuja
chave é nula — é por isso que a raiz de uma hierarquia, com pai NULL, some de
uma autojunção interna.
Transações. COMMIT confirma, ROLLBACK desfaz a transação corrente a
partir do log (não de backup), e SAVEPOINT marca um ponto intermediário ao
qual se pode voltar sem abortar tudo. No MySQL o autocommit vem ligado e cada
comando já é uma transação; START TRANSACTION o suspende. No PostgreSQL o
DDL é transacional, o que produz o item abaixo:
begin;
savepoint primeiro;
create table tbl_conceito (id int, nome varchar);
rollback to savepoint primeiro;
commit;
-- a tabela NÃO é criada: o DDL foi desfeito junto com o resto
Em Oracle e MySQL, ao contrário, o DDL provoca commit implícito e não há o que desfazer. O SGBD citado no item decide a resposta.
DCL. GRANT admite privilégio em nível de coluna e o papel PUBLIC
representa todos os usuários. O privilégio recai sobre os dados da tabela:
GRANT DELETE ON Hospital autoriza apagar linhas, jamais a tabela. Com
WITH GRANT OPTION, o beneficiário pode repassar o privilégio adiante sem
consultar o proprietário.
O que decide os itens
Os pares que a banca troca. Cada linha é um item inteiro do corpus.
| isto | não é isto |
|---|---|
WHERE filtra linhas, antes de agregar | HAVING filtra grupos, depois |
WHERE = seleção (σ) da álgebra | lista do SELECT = projeção (π) |
| produto cartesiano = condição ausente | condição correta é o que o evita |
UNION elimina duplicatas | UNION ALL as mantém |
| view guarda a consulta | view materializada guarda o resultado |
DELETE apaga linhas | DROP elimina o objeto |
UPDATE muda valores | ALTER TABLE muda a definição |
CREATE DATABASE cria banco | CREATE TABLE cria tabela |
ROLLBACK desfaz pelo log | restore recupera pelo backup |
| DML modifica dados | DDL modifica estrutura |
| CRUD termina em Delete | não em Drop |
A ordem das cláusulas é obrigatória: SELECT, FROM, WHERE, GROUP BY,
HAVING, ORDER BY. Item que põe GROUP BY ou HAVING antes do WHERE, ou
WHERE depois de ORDER BY/LIMIT, está errado por sintaxe, antes mesmo do
mérito. Obrigatórias mesmo, só SELECT e FROM.
Quando o item exibe uma consulta e promete um resultado, cheque nesta ordem — é mais rápido e costuma decidir sozinho:
- Há
GROUP BY? Se o item promete “total por X” e não há, a soma é única para toda a consulta e o item cai aí. - Quantos grupos? O número de linhas do resultado é o de valores distintos das colunas agrupadas.
- O
HAVINGestá no limite?> 45não retém um grupo que soma exatamente 45. É onde a banca esconde a diferença entre uma e duas linhas. - Há
ORDER BY? Sem ele, nenhuma ordem é garantida — nem a de inserção. - A junção é interna ou externa? E, se externa, há o
IS NULLque a transforma em antijunção?
Classificação do SELECT: depende do próprio enunciado. Este é o único ponto
do assunto em que dois itens com a mesma aparência têm gabaritos opostos, e o
corpus traz os dois:
- “os comandos SELECT e UPDATE fazem parte da DML” — Certo. O caderno opõe
apenas DDL e DML, e nessa divisão o
SELECTé DML. - “o comando SELECT nome, idade FROM CLIENTE; pertence à DML” — Errado. O
enunciado desse caderno já havia distinguido DDL, DML e DQL; havendo DQL,
o
SELECTé DQL.
Leia o enunciado do bloco antes de escolher a sigla.
Sintaxe que cai literalmente.
| construção | forma correta |
|---|---|
| inserir uma linha | INSERT INTO tabela VALUES (...) — a tabela vem antes do VALUES |
| inserir duas linhas | dois pares de parênteses após VALUES, separados por vírgula |
| literal de texto | entre apóstrofos, sempre — inclusive CNPJ e CEP |
| começa com “a” | WHERE NOME LIKE 'a%' — curinga só funciona com LIKE, e o LIKE distingue maiúsculas de minúsculas: sobre dados em caixa alta, 'a%' não casa com nada |
| remover coluna | ALTER TABLE t DROP COLUMN c |
| remover linha | DELETE FROM t WHERE ... |
| chave estrangeira | a tabela referenciada já tem de existir; par circular exige ALTER TABLE depois |
Desempenho. O critério é sempre um só: o predicado permite ao otimizador usar o índice?
- Subconsulta correlacionada é reavaliada por linha → piora.
ORsobre colunas diferentes impede o índice; reescrever comoUNIONmelhora.- Conversão implícita na coluna anula o índice; converta o parâmetro
(
CASTno lado do parâmetro, não no lado da coluna). SELECT *traz colunas desnecessárias e aumenta memória e E/S.- Trocar
UPDATEporDELETEmaisINSERTpiora: são duas operações, dois conjuntos de registros de log e todos os índices mantidos duas vezes.
Como a CEBRASPE derruba você aqui
Medido sobre os 145 itens do tópico, todos explicados: 60 Certos e 85 Errados. Nos 85 Errados: atribuição errada 24 (28%), troca de termo 22 (26%), inversão 17 (20%), generalização 9 (11%), número errado 5 (6%), exceção omitida 4 (5%), relação causal 2 e escopo ampliado 2.
A etiqueta erra mais que a consulta. Vinte e dois itens do tópico perguntam a
que sublinguagem pertence um comando, e treze deles são Errados — é o maior
bolo de itens errados do assunto, e um dos dois únicos recortes em que os Errados
superam os Certos (o outro é view). O comando é descrito com precisão e recebe a
sigla do vizinho: “No DML (data manipulation language), a instrução
TRUNCATE”; “A operação para adicionar uma coluna nova à tabela vendas é realizada
por meio de DML”; “A DDL é utilizada em bancos de dados para comandos de
UPDATE nas tabelas”; “SELECT é uma instrução de controle de banco de
dados”; “São comandos DDL: CREATE, TRUNCATE, GRANT e ROLLBACK”; “a
criação de uma view… é considerada operação de DML, pois envolve a
estrutura lógica”; “A DML é uma linguagem que interage com os objetos do banco
de dados, em vez de interagir com os dados”. Todos caem com a mesma leitura:
leia o verbo, não o objeto nem a justificativa. CREATE VIEW é DDL mesmo que
a view seja feita de SELECT; UPDATE é DML mesmo que o item fale em
“definição”; TRUNCATE é DDL mesmo esvaziando linhas; GRANT é DCL e ROLLBACK
é TCL, nunca DDL.
Troca de termo, 22 itens: o comando vizinho. Aqui o rótulo descreve bem o que
acontece — uma palavra é substituída pela de ao lado e o resto da frase fica
intacto: “deve-se fazer uso do comando DELETE TABLE” (não existe); “O
comando SQL MODIFY” tratado como comando próprio (é cláusula do ALTER TABLE);
“permite criar uma tabela de nome aluno” para um create database aluno; “o
privilégio de remoção da tabela Hospital” para um GRANT DELETE; “(Create,
Read, Update, Drop)” na sigla CRUD; “WHERE NOME = '%a%'” com curinga sem
LIKE. Leia o verbo e o objeto imediatamente depois dele, e ignore o resto da
frase na primeira passada.
Inversão, 17 itens, e três pares concentram quase tudo. Projeção × seleção:
“a cláusula WHERE… corresponde à operação de projeção”, “a cláusula FROM
corresponde à seleção do predicado”. Antes × depois: “GROUP BY e HAVING…
definidas sempre antes da cláusula WHERE”; “o produto cartesiano ocorrerá
quando a condição de união estiver corretamente especificada”; “a cláusula
WHERE define que o resultado da consulta é o produto cartesiano”. O operador
e seu oposto: “o operador UNION não elimina os registros duplicados”;
“tuplas duplicadas são automaticamente eliminadas pelo SGBD”; um EXISTS que
“lista os hospitais que não tiveram gastos” (falta o NOT); “não é
possível excluir uma restrição do tipo PRIMARY KEY por meio do comando ALTER
TABLE”; a subconsulta correlacionada que “aumenta o desempenho”. O
encadeamento lógico do começo desta nota desfaz o grupo inteiro sem cálculo
nenhum.
View é o objeto mais repetido do tópico: 16 itens, 11 errados. Mas a distorção não é só uma. Três itens dizem que a view comum tem corpo físico — “ocupando espaço físico no banco de dados”, “são armazenadas em disco”, “geração de uma tabela física” —, e a regra vale: se o item não escreveu a palavra “materializada”, a resposta é virtual. Os outros oito atacam pontos diferentes, e vale saber quais são, porque só a regra acima não os pega: a materializada descrita ao contrário (“armazena apenas a consulta que define e apresenta o resultado sempre atualizado”); a atualização por view tratada como irrestrita (“Views não inserem restrições à realização de consultas, inserções, atualizações e exclusões”); a view como visão única da base (“todos os usuários devem possuir uma mesma visão”); a independência lógica invertida (“que exibem para os aplicativos as alterações feitas no esquema conceitual” — a view existe justamente para isolar o aplicativo delas); e o privilégio, que se concede sobre a view e não se herda da tabela base.
Quarenta e um itens exibem código e prometem um resultado, e vinte e um deles
são Errados — metade exata. Não julgue
pela aparência do código: monte a tabela e execute a consulta na cabeça. Foi
assim que se decidiu que HAVING ValorTotal > 45 devolve uma linha e não
duas, que a junção com MAX(versao) GROUP BY idsoft devolve dois registros e
não três, e que LIMIT conta o que sai, não o que se pula.
NULL decide, mas não pela comparação. Os quatro itens de exceção omitida são
todos de NULL, e nenhum deles é o clássico = NULL contra IS NULL — esse
literalmente não aparece no corpus. O que aparece é nulo em conta e em
agregação: “a execução do código SQL a seguir retornará 10” para
SELECT a+10 sobre uma linha nula (nulo propaga: o resultado é nulo);
COUNT(a), AVG(a) sobre três linhas com uma nula anunciado como “3 | 4”
(é 2 e 6, porque a agregação ignora nulos e o COUNT(*) é que não ignoraria);
MAX sobre um LIKE 'a%' que não casou com nada, anunciado como 70 (sobre
conjunto vazio, MAX devolve nulo, e só COUNT devolveria zero); e a antijunção
NOT IN declarada idêntica a um LEFT JOIN sem o WHERE ... IS NULL. Some
a esses o item que nega ao índice bitmap a indexação de nulos — a restrição é do
B-tree. Saiba a lógica de três valores pela aritmética e pela agregação, que é
onde ela cai.
Restrição indevida, 9 itens, e o padrão é sempre fechar uma alternativa que a
linguagem mantém aberta: “Somente são possíveis os seguintes quatro tipos de
JOIN” (falta o FULL OUTER JOIN); “usada somente no SQL Server”; a função de
agregação que “deve ser combinada com a cláusula GROUP BY” (sem ele, a tabela
inteira é um grupo); “duas instruções SELECT quaisquer” num UNION;
“necessariamente uma lista… ordenados pelo campo Preco” sem ORDER BY; e o
verbo de garantia em item de desempenho — trocar UPDATE por DELETE mais
INSERT “garantiria melhor desempenho”.
Cinco itens erram um número, e nenhum deles é um número de sintaxe — são sempre a quantidade de linhas que a consulta devolve, ou o valor que ela calcula. O caminho para conferi-los é o do bloco anterior: executar.
Erros clássicos
Achar que WHERE cria o produto cartesiano. É o FROM que combina tudo; o
WHERE é o que reduz. Vale nos dois sentidos: nem o WHERE produz o produto
cartesiano, nem a condição bem escrita o provoca.
Confiar na ordem sem ORDER BY. Nenhuma ordem é garantida — nem a de
inserção, nem a da chave primária, nem a que apareceu na última execução.
Ler TRUNCATE como DML. Ele esvazia a tabela como um DELETE sem WHERE,
mas é DDL: não aceita WHERE, não dispara trigger de linha e, em regra, não é
desfeito por ROLLBACK.
Dar ao SELECT uma sigla fixa. Ele é DQL quando o enunciado fala em DQL e
DML quando o enunciado só opõe DDL e DML.
Esquecer o IS NULL da antijunção. LEFT JOIN sozinho devolve tudo. Quem
transforma a junção externa em “os que não têm par” é o filtro sobre a coluna
nula.
Comparar com NULL usando =. Nunca casa. E NOT IN sobre uma subconsulta
que devolva um único NULL não retorna linha alguma — troque por NOT EXISTS.
Achar que UNION aceita quaisquer dois SELECT. Mesmo número de colunas,
tipos compatíveis, mesma ordem — senão o comando é rejeitado.
Supor que o GROUP BY exige função de agregação. Sem ela, ele apenas devolve
as combinações distintas, como um DISTINCT. E nada nele depende de ORDER BY.
Contar com o ROLLBACK para desfazer DDL em qualquer SGBD. No PostgreSQL,
sim. Em Oracle e MySQL o DDL confirma implicitamente a transação.
Imaginar que a herança do PostgreSQL compartilha a sequência. A tabela filha
tem IDENTITY própria: inserir nela não avança o contador da tabela pai. O
SELECT na tabela pai, esse sim, enxerga as linhas das descendentes.
LidoPraticado