SQL ANSI – Operadores Lógicos, NULL e Junções
Gabarito: letra A. A consulta da alternativa A está sintaticamente correta e retorna exatamente uma linha, porque aplica corretamente a precedência de operadores lógicos (AND tem precedência sobre OR, e o parêntese isola a disjunção) sobre os dados da tabela emp. As demais alternativas contêm erros conceituais: comparação com NULL usando <> (alternativa C), contagem incorreta de linhas em LEFT JOIN (alternativa D) e junção com duplicação de linhas (alternativa E).
A questão cobra o domínio de três pilares da linguagem SQL: a precedência e a semântica dos operadores lógicos (AND, OR, NOT), o tratamento de valores nulos (que não podem ser comparados com operadores de igualdade/desigualdade) e o comportamento das junções (JOIN), especialmente o LEFT JOIN e o produto cartesiano com filtro. Vamos entender cada um desses conceitos para depois analisar cada alternativa com precisão.
1. Precedência de operadores lógicos: Em SQL, assim como na álgebra booleana, o operador NOT tem a maior precedência, seguido por AND e, por último, OR. Isso significa que, sem parênteses, a expressão A OR B AND C é interpretada como A OR (B AND C). Os parênteses servem justamente para alterar essa ordem de avaliação, forçando que a expressão dentro deles seja avaliada primeiro. Na alternativa A, a condição (NOT funcao = 'Encarregado' OR ndep = 20) é avaliada como um bloco único, e o resultado desse bloco é combinado com ndep = 10 usando AND. Essa é a leitura correta da consulta.
2. O tratamento de NULL: O valor NULL representa ausência de informação. Qualquer comparação aritmética ou lógica envolvendo NULL (como =, <>, <, >) resulta em UNKNOWN, não em TRUE ou FALSE. Na cláusula WHERE, apenas as linhas cuja condição avalia para TRUE são retornadas; linhas com UNKNOWN ou FALSE são descartadas. Para testar a presença de NULL, o SQL fornece os operadores IS NULL e IS NOT NULL. Usar <> NULL é um erro clássico que nunca retorna linhas, pois a comparação sempre resulta em UNKNOWN.
3. Junções (JOIN): O LEFT JOIN (ou LEFT OUTER JOIN) retorna todas as linhas da tabela à esquerda (a primeira mencionada no FROM), combinadas com as linhas correspondentes da tabela à direita. Se não houver correspondência, os campos da tabela à direita são preenchidos com NULL. Já o produto cartesiano (junção implícita sem condição) combina cada linha de uma tabela com todas as linhas da outra; quando há uma condição de junção no WHERE, o resultado é equivalente a um INNER JOIN, retornando apenas as combinações que satisfazem a condição. A contagem de linhas resultante depende dos dados e da condição.
Agora, com esses conceitos claros, vamos analisar cada alternativa em detalhe.
Alternativa | Análise | Veredito |
|---|
A | Aplica corretamente a precedência de operadores lógicos (AND > OR, com parênteses isolando a disjunção); retorna exatamente 1 linha. | ✅ Correta |
B | Comparação de strings é case-sensitive no padrão ANSI; 'JORGE SAMPAIO' ≠ 'Jorge Sampaio'. | ❌ Incorreta |
C | premios <> NULL resulta em UNKNOWN; nenhuma linha é retornada (deveria usar IS NOT NULL).
| ❌ Incorreta |
D | LEFT JOIN retorna todas as 11 linhas da tabela à esquerda, não 10.
| ❌ Incorreta |
E | Junção emp × dep com condição e.ndep = d.ndep retorna 11 linhas (uma por empregado), não 9. | ❌ Incorreta |
Alternativa A — ✅ Correta ⟵ GABARITO
A consulta SELECT * FROM emp WHERE ndep = 10 AND (NOT funcao = 'Encarregado' OR ndep = 20); está sintaticamente correta e retorna uma linha. Vamos decompor a lógica:
ndep = 10: filtra os empregados do departamento 10. Conforme os dados da tabela emp, os empregados com ndep = 10 são os de nemp 1839 e 1782.
(NOT funcao = 'Encarregado' OR ndep = 20): este bloco é avaliado para cada um desses dois empregados:
Para nemp = 1839: a função não é 'Encarregado', então NOT funcao = 'Encarregado' é TRUE. Como é um OR, o bloco inteiro é TRUE.
Para nemp = 1782: a função é 'Encarregado', então NOT funcao = 'Encarregado' é FALSE. Além disso, ndep = 20 é FALSE (pois ndep = 10). Logo, o bloco é FALSE.
AND: combina as duas condições. Para nemp = 1839, TRUE AND TRUE = TRUE → linha retornada. Para nemp = 1782, TRUE AND FALSE = FALSE → linha descartada.
Portanto, apenas uma linha é retornada, confirmando a alternativa como correta.
Alternativa B — ❌ Incorreta
A alternativa afirma que as duas consultas apresentam o mesmo resultado. Isso é falso porque, no padrão SQL ANSI, a comparação de strings é case-sensitive (sensível a maiúsculas e minúsculas) por padrão. Assim, 'JORGE SAMPAIO' e 'Jorge Sampaio' são valores diferentes, e a consulta com WHERE NOME = 'JORGE SAMPAIO' retornará apenas os registros com o nome exatamente em maiúsculas, enquanto a consulta com WHERE nome = 'Jorge Sampaio' retornará apenas os registros com essa capitalização específica. Se houver um registro com o nome 'JORGE SAMPAIO', a primeira consulta o retorna, mas a segunda não, e vice-versa. Portanto, os resultados não são equivalentes.
É importante notar que, embora os identificadores (nomes de colunas e palavras-chave) sejam case-insensitive no padrão ANSI, os dados (valores literais) são case-sensitive. Essa distinção é crucial e frequentemente cobrada em provas.
Alternativa C — ❌ Incorreta
A consulta SELECT nome "Com Premios" FROM emp WHERE premios <> NULL; não retornará nenhuma linha, e não quatro como afirma a alternativa. O erro está na condição premios <> NULL. Conforme explicado, qualquer comparação com NULL usando operadores de comparação (=, <>, <, >, etc.) resulta em UNKNOWN, e a cláusula WHERE descarta linhas cuja condição não seja TRUE. Portanto, nenhuma linha é retornada. A forma correta de verificar se um valor não é nulo é usar premios IS NOT NULL.
Alternativa D — ❌ Incorreta
A alternativa afirma que o LEFT JOIN retornará dez linhas, mas o correto é que retornará onze linhas. O LEFT JOIN entre emp e1 e emp e2 na condição e2.nemp = e1.encar retorna todas as linhas da tabela da esquerda (e1), que é a tabela emp completa. Como a tabela emp tem 11 registros, o resultado terá no mínimo 11 linhas. Para cada empregado que tem um encarregado (ou seja, e1.encar corresponde a um e2.nemp), a linha é combinada com o registro do encarregado. Para o empregado que não tem encarregado (se houver), os campos de e2 serão NULL. Portanto, o número de linhas é 11, não 10.
Alternativa E — ❌ Incorreta
A alternativa afirma que a consulta com junção implícita (FROM emp e, dep d WHERE e.ndep = d.ndep) retornará nove linhas. Para verificar, precisamos dos dados das tabelas. A tabela emp tem 11 registros, e a tabela dep tem 3 registros (departamentos 10, 20 e 30). A condição e.ndep = d.ndep combina cada empregado com o departamento correspondente. Como cada empregado pertence a um único departamento, e cada departamento tem um único registro em dep, o resultado terá 11 linhas (uma para cada empregado), não 9. A alternativa erra na contagem.
Conclusão: A única alternativa correta é a letra A, pois a consulta está sintaticamente correta e retorna exatamente uma linha, conforme a análise da precedência dos operadores lógicos e dos dados da tabela emp.
Gabarito: letra A