---
metadata:
  - name: generator
    content: Diplodoc Platform v5.61.1
alternate:
  - https://ydb.tech/docs/en/yql/reference/syntax/correlated-subqueries.md
  - https://ydb.tech/docs/ru/yql/reference/syntax/correlated-subqueries.md
  - href: https://ydb.tech/docs/ru/yql/reference/syntax/correlated-subqueries.md
    type: text/markdown
    title: Markdown version
  - href: https://ydb.tech/docs/ru/llms.txt
    rel: describedby
sourcePath: ru/core/yql/reference/syntax/correlated-subqueries.md
---
> **Documentation Index:** Fetch the complete configuration index at https://ydb.tech/docs/ru/llms.txt

# Коррелированные подзапросы, EXISTS и NOT EXISTS

Коррелированный подзапрос обращается к колонке или псевдониму таблицы из внешнего запроса. Каждый подзапрос в YQL имеет собственную область видимости и не может обращаться к колонкам или псевдонимам таблиц из внешнего запроса. Поэтому YQL не поддерживает коррелированные подзапросы. Поддержку коррелированных подзапросов планируется добавить в следующих релизах.

## Матрица поддержки {#support-matrix}

| SQL-шаблон | Поддержка в YQL | Что использовать |
| --- | --- | --- |
| Некоррелированный подзапрос во `FROM` или `IN` | Поддерживается | Используйте подзапрос непосредственно |
| Некоррелированный `EXISTS (SELECT ...)` | Поддерживается; возвращает `true`, если подзапрос содержит хотя бы одну строку | Используйте непосредственно, если условие не зависит от строки внешнего запроса |
| Некоррелированный `NOT EXISTS (SELECT ...)` | Поддерживается; возвращает `true`, если подзапрос пуст | Используйте непосредственно, если условие не зависит от строки внешнего запроса |
| `EXISTS` с обращением к внешней колонке | Не поддерживается | `LEFT SEMI JOIN` или `INNER JOIN` с уникальными ключами справа |
| `NOT EXISTS` с обращением к внешней колонке | Не поддерживается | `LEFT ONLY JOIN` |
| Коррелированный скалярный подзапрос или подзапрос с агрегацией | Не поддерживается | Предварительно вычислите результат и используйте `JOIN` |

## EXISTS {#exists}

Некоррелированный `EXISTS` проверяет, содержит ли его подзапрос хотя бы одну строку. Его результат не зависит от строки внешнего запроса. Например, следующий запрос возвращает всех клиентов, если таблица `orders` не пуста, и не возвращает ни одного клиента, если она пуста:

```yql
SELECT client_id, name
FROM clients
WHERE EXISTS (
    SELECT 1
    FROM orders
);
```

Следующий распространённый SQL-запрос не поддерживается, поскольку внутренний запрос обращается к внешнему псевдониму `c`:

```yql
-- Не поддерживается в YQL.
SELECT c.client_id, c.name
FROM clients AS c
WHERE EXISTS (
    SELECT 1
    FROM orders AS o
    WHERE o.client_id = c.client_id
);
```

Чтобы вернуть клиента, только если существует хотя бы один подходящий заказ, используйте `LEFT SEMI JOIN`:

```yql
SELECT c.client_id, c.name
FROM clients AS c
LEFT SEMI JOIN orders AS o
ON o.client_id = c.client_id;
```

`LEFT SEMI JOIN` возвращает только колонки левой стороны. Несколько подходящих строк справа не дублируют строку слева, поэтому такое преобразование сохраняет семантику проверки существования.

В качестве альтернативы используйте `INNER JOIN`, предварительно удалив повторяющиеся ключи с правой стороны:

```yql
$order_clients = (
    SELECT client_id
    FROM orders
    GROUP BY client_id
);

SELECT c.client_id, c.name
FROM clients AS c
INNER JOIN $order_clients AS o
ON o.client_id = c.client_id;
```

Правая сторона содержит не более одной строки для каждого ключа, поэтому соединение не дублирует строки слева. Применять `DISTINCT` к колонкам левой стороны не требуется: он может объединить одинаковые строки внешней выборки.

Для одного неопционального ключа запрос можно также переписать через `IN`:

```yql
SELECT c.client_id, c.name
FROM clients AS c
WHERE c.client_id IN (
    SELECT o.client_id
    FROM orders AS o
);
```

## NOT EXISTS {#not-exists}

Некоррелированный `NOT EXISTS` возвращает результат, обратный `EXISTS`: `true`, если подзапрос пуст, и `false`, если подзапрос содержит хотя бы одну строку. Его результат также не зависит от строки внешнего запроса.

Чтобы вернуть клиента, только если подходящих заказов нет, используйте `LEFT ONLY JOIN`:

```yql
SELECT c.client_id, c.name
FROM clients AS c
LEFT ONLY JOIN orders AS o
ON o.client_id = c.client_id;
```

## Коррелированные подзапросы с агрегацией {#correlated-aggregate}

Предварительно вычислите агрегат и присоедините его к внешней таблице:

```yql
$last_order = (
    SELECT client_id, MAX(created_at) AS last_order_at
    FROM orders
    GROUP BY client_id
);

SELECT c.client_id, o.last_order_at
FROM clients AS c
LEFT JOIN $last_order AS o
ON o.client_id = c.client_id;
```

## См. также

- [JOIN](https://ydb.tech/docs/ru/yql/reference/syntax/select/join.md)
- [Выражения: IN](https://ydb.tech/docs/ru/yql/reference/syntax/expressions.md#in)
- [Известные ограничения](https://ydb.tech/docs/ru/analyst/limitations.md)
