Какие есть способы сделать выборку из двух таблиц, кроме использования JOIN?

«Какие есть способы сделать выборку из двух таблиц, кроме использования JOIN?» — вопрос из категории Базы данных, который задают на 24% собеседований PHP Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Хотя JOIN — основной инструмент для реляционных запросов, иногда нужны альтернативы. Вот методы, которые я использовал в зависимости от задачи:

1. Подзапросы (Subqueries) Идеально, когда результат из одной таблицы нужен только как условие для фильтрации в другой.

-- Найти всех пользователей, которые делали заказы (аналог INNER JOIN)
SELECT * FROM users 
WHERE id IN (SELECT DISTINCT user_id FROM orders);

-- Найти товары, цена которых выше средней (связанность не через ключ)
SELECT * FROM products 
WHERE price > (SELECT AVG(price) FROM products);

2. Операции над множествами: UNION / UNION ALL Используются для объединения результатов из разных таблиц с одинаковой структурой, а не для их связывания.

-- Объединить список email из двух таблиц (например, подписчики и клиенты)
SELECT email, 'subscriber' as source FROM newsletter_subscribers
UNION ALL -- UNION ALL не удаляет дубли, работает быстрее
SELECT email, 'customer' as source FROM customers;
-- Простой UNION удалит дублирующиеся строки.

3. Коррелированные подзапросы в SELECT или WHERE Позволяют "притянуть" одно значение из связанной таблицы для каждой строки основной.

-- Для каждого заказа получить имя клиента (менее эффективно, чем JOIN, но наглядно)
SELECT 
    id,
    amount,
    (SELECT name FROM clients WHERE clients.id = orders.client_id) as client_name
FROM orders;

4. Отдельные запросы + обработка на уровне приложения Иногда это оправдано:

  • Для сложной, нереляционной логики, которую проще реализовать в коде.
  • При работе с разнородными источниками данных (например, SQL + NoSQL).
  • Для пагинации сложных объединённых данных, где JOIN может работать медленно.

Пример (псевдокод на PHP):

$users = $pdo->query("SELECT id, name FROM users WHERE active = 1")->fetchAll();
$userIds = array_column($users, 'id');
$placeholders = implode(',', array_fill(0, count($userIds), '?'));

$orders = $pdo->prepare("SELECT * FROM orders WHERE user_id IN ($placeholders)");
$orders->execute($userIds);
$ordersData = $orders->fetchAll();

// Далее вручную сопоставляем users и orders в массиве $result

Когда что выбирать:

  • JOIN — для выборки связанных данных из разных таблиц в одной результирующей строке.
  • Подзапросы — для фильтрации или вычисления значений на основе другой таблицы.
  • UNION — для сложения наборов строк.
  • Отдельные запросы — когда реляционная модель не справляется или нужен полный контроль над производительностью.