← tópicos

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).

siglacomandoso que toca
DDLCREATE, ALTER, DROP, TRUNCATEa estrutura e o catálogo (metadados)
DMLINSERT, UPDATE, DELETEas linhas
DQLSELECTnada; só recupera
DCLGRANT, REVOKEprivilégios
TCLCOMMIT, ROLLBACK, SAVEPOINTa 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.

tipopreserva
INNER JOINsó os pares que casam
LEFT JOINtodas as linhas da tabela à esquerda, com NULL à direita
RIGHT JOINtodas as da direita
FULL JOINas duas
CROSS JOINo 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.

istonão é isto
WHERE filtra linhas, antes de agregarHAVING filtra grupos, depois
WHERE = seleção (σ) da álgebralista do SELECT = projeção (π)
produto cartesiano = condição ausentecondição correta é o que o evita
UNION elimina duplicatasUNION ALL as mantém
view guarda a consultaview materializada guarda o resultado
DELETE apaga linhasDROP elimina o objeto
UPDATE muda valoresALTER TABLE muda a definição
CREATE DATABASE cria bancoCREATE TABLE cria tabela
ROLLBACK desfaz pelo logrestore recupera pelo backup
DML modifica dadosDDL modifica estrutura
CRUD termina em Deletenã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:

  1. 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í.
  2. Quantos grupos? O número de linhas do resultado é o de valores distintos das colunas agrupadas.
  3. O HAVING está no limite? > 45 não retém um grupo que soma exatamente 45. É onde a banca esconde a diferença entre uma e duas linhas.
  4. ORDER BY? Sem ele, nenhuma ordem é garantida — nem a de inserção.
  5. A junção é interna ou externa? E, se externa, há o IS NULL que 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:

Leia o enunciado do bloco antes de escolher a sigla.

Sintaxe que cai literalmente.

construçãoforma correta
inserir uma linhaINSERT INTO tabela VALUES (...) — a tabela vem antes do VALUES
inserir duas linhasdois pares de parênteses após VALUES, separados por vírgula
literal de textoentre 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 colunaALTER TABLE t DROP COLUMN c
remover linhaDELETE FROM t WHERE ...
chave estrangeiraa 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?

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 INSERTgarantiria 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.

Praticar145 itens