TGViewer
SQL Ready | Базы Данных SQL Ready | Базы Данных @sql_ready · 17.5K subscribers
Post #1818 2.13K
SEMI JOIN через EXISTS — как корректно проверять наличие связанных строк!

Частая задача в SQL — выбрать строки из одной таблицы, если в другой таблице существует хотя бы одна связанная запись.

Таблицы:
customers(id, name)
orders(id, customer_id, created_at)


Нужно получить клиентов, у которых есть хотя бы один заказ.

Попытка через JOIN:
SELECT
c.id,
c.name
FROM customers c
JOIN orders o
ON o.customer_id = c.id;


Запрос вернёт клиентов, но если у клиента несколько заказов, он появится в результате несколько раз.

Чтобы убрать дубликаты, часто добавляют DISTINCT:
SELECT DISTINCT
c.id,
c.name
FROM customers c
JOIN orders o
ON o.customer_id = c.id;


Результат будет корректным, однако такой запрос выражает задачу менее точно: JOIN формирует строки для каждого совпадения, а DISTINCT затем устраняет повторяющиеся значения.

В подобных задачах фактически требуется semi join — вернуть строку из customers, если существует хотя бы одна связанная строка в orders.

В большинстве СУБД это обычно выражают через EXISTS:
SELECT
c.id,
c.name
FROM customers c
WHERE EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.id
);


Подзапрос проверяет наличие хотя бы одной строки в orders, связанной с текущим клиентом.

Оптимизатор часто может завершить проверку сразу после нахождения первого совпадения, поэтому EXISTS является естественным инструментом для проверки существования строк.

Практический пример — клиенты, которые делали заказы после определённой даты:
SELECT
c.id,
c.name
FROM customers c
WHERE EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.id
AND o.created_at >= '2025-01-01'
);


EXISTS не возвращает данные из подзапроса — он только проверяет факт существования строки.

Поэтому внутри обычно пишут:
SELECT 1


или:
SELECT *


В контексте EXISTS список выбираемых выражений не влияет на результат.

🔥 EXISTS — стандартный и выразительный способ реализовать semi join. Он точно отражает намерение запроса и часто позволяет оптимизатору построить более эффективный план выполнения.

➡️ SQL Ready | #практика
  • 👍 13
  • 🔥 9
  • ❤ 6
  • 🤝 6
More from @sql_ready
  1. Oct 7, 2026📂 Шпаргалка по паттернам распределённых систем! Например, Replication повышает доступност…
  2. Oct 6, 2026Проверяйте связи с учётом периода! В PostgreSQL 18 связь может учитывать ещё и период его…
  3. Oct 6, 2026⚡️5 фундаментальных курсов по ИБ по цене одного Это предложение для тех, кто готов войти в…
  4. Oct 6, 2026👍 Устройство PostgreSQL — подробная документация на русском языке! Материалы посвящены не…
  5. Oct 5, 2026COUNT(*) в PostgreSQL: MVCC, visibility map и стоимость выполнения! В PostgreSQL точный CO…
  6. Oct 5, 2026Как оплачивать зарубежные сервисы в 2026 году? Можно бегать между посредниками и бояться б…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →