DBAtlas · Atlas de operações de banco de dados

EXISTS / IN / NOT EXISTS (subconsulta)

Oracle

-- Customers with orders (EXISTS)
SELECT name FROM customer m
WHERE EXISTS (SELECT 1 FROM orders s WHERE s.customer_id = m.id);

-- List membership with IN
SELECT name FROM customer
WHERE city IN ('Ankara', 'Izmir');

-- Customers with no orders at all (NOT EXISTS)
SELECT name FROM customer m
WHERE NOT EXISTS (SELECT 1 FROM orders s WHERE s.customer_id = m.id);

EXISTS verifica se uma subconsulta correlacionada retorna pelo menos uma linha (para na primeira correspondência, por isso é rápido). IN verifica se um valor está em uma lista/resultado de subconsulta. Atenção: se a subconsulta puder produzir NULL, NOT IN gera resultados inesperados; NOT EXISTS é mais seguro. O otimizador do Oracle frequentemente transforma ambos no mesmo plano.

PostgreSQL

SELECT name FROM customer m
WHERE EXISTS (SELECT 1 FROM orders s WHERE s.customer_id = m.id);

SELECT name FROM customer
WHERE city IN (SELECT city FROM target_cities);

SELECT name FROM customer m
WHERE NOT EXISTS (SELECT 1 FROM orders s WHERE s.customer_id = m.id);

O PostgreSQL suporta totalmente EXISTS/IN/NOT EXISTS. Com NOT IN, se a subconsulta contiver NULL, o resultado inteiro pode ficar vazio; por isso, recomenda-se NOT EXISTS ou LEFT JOIN ... IS NULL. Na maioria dos casos, o planner trata IN e EXISTS de forma equivalente, como um semi-join.

MySQL

SELECT name FROM customer m
WHERE EXISTS (SELECT 1 FROM orders s WHERE s.customer_id = m.id);

SELECT name FROM customer
WHERE city IN ('Ankara', 'Izmir');

SELECT name FROM customer m
WHERE NOT EXISTS (SELECT 1 FROM orders s WHERE s.customer_id = m.id);

O MySQL/MariaDB suportam EXISTS/IN/NOT EXISTS. Antes do MySQL 5.6, subconsultas correlacionadas podiam ser lentas; o 5.6+ acelerou as subconsultas IN com otimizações de semi-join e materialização. A armadilha NOT IN + NULL também se aplica aqui.

SQL Server

SELECT name FROM customer m
WHERE EXISTS (SELECT 1 FROM orders s WHERE s.customer_id = m.id);

SELECT name FROM customer
WHERE city IN (SELECT city FROM target_cities);

SELECT name FROM customer m
WHERE NOT EXISTS (SELECT 1 FROM orders s WHERE s.customer_id = m.id);

O SQL Server suporta EXISTS/IN/NOT EXISTS, e o otimizador geralmente os processa como semi/anti-joins. Se uma subconsulta NOT IN contiver NULL, o resultado pode ficar inesperadamente vazio; NOT EXISTS é a escolha segura. INTERSECT/EXCEPT também podem ser usados para lógica de pertinência semelhante.

MongoDB

// IN equivalent: the $in operator
db.customer.find({ city: { $in: ["Ankara", "Izmir"] } })

// EXISTS equivalent: match check with $lookup + $match
db.customer.aggregate([
  { $lookup: { from: "orders", localField: "id",
      foreignField: "customer_id", as: "s" } },
  { $match: { "s.0": { $exists: true } } }  // at least one order
])

No MongoDB, a pertinência a uma lista de valores é feita com os operadores $in / $nin. O equivalente a um EXISTS de subconsulta é obter o array de documentos correspondentes com $lookup e filtrar se o array está vazio. Verificar a existência de um campo é um operador separado, { field: { $exists: true } } (presença de um campo, não uma relação entre linhas).

Redis

# Membership check with Set/Hash:
SISMEMBER target_cities "Ankara"   # is it in the set? (IN-like)
EXISTS customer:1                 # does the key exist?

O Redis não tem subconsultas. Para pertinência de valores, use SISMEMBER em um Set (semelhante a IN). O comando EXISTS não é uma subconsulta; ele retorna se a chave informada existe. Verificações de existência relacionais são feitas no lado da aplicação lendo várias chaves.

Elasticsearch

# IN equivalent: terms query
GET customer/_search
{ "query": { "terms": { "city": ["Ankara", "Izmir"] } } }

# Field existence: exists query
GET customer/_search
{ "query": { "exists": { "field": "phone" } } }

No Elasticsearch, o equivalente a IN é a consulta 'terms' (corresponde a um entre vários valores), e NOT IN é terms dentro de bool must_not. A consulta 'exists' não corresponde ao EXISTS do SQL; ela verifica se um campo tem valor no documento. Um EXISTS correlacionado entre tabelas geralmente exige desnormalização.

Abrir no DBAtlas →