> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-mintlify-8a08bda2.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Документация по предложению LIMIT BY

# Предложение LIMIT BY

Запрос с предложением `LIMIT n BY expressions` выбирает первые `n` строк для каждого уникального значения `expressions`. Ключ для `LIMIT BY` может содержать любое количество [expressions](/ru/reference/syntax#expressions).

ClickHouse поддерживает следующие варианты синтаксиса:

* `LIMIT [offset_value, ]n BY expressions`
* `LIMIT n OFFSET offset_value BY expressions`

Во время обработки запроса ClickHouse выбирает данные, упорядоченные по ключу сортировки. Ключ сортировки задается явно с помощью предложения [ORDER BY](/ru/reference/statements/select/order-by) или неявно как свойство движка таблицы (порядок строк гарантируется только при использовании [ORDER BY](/ru/reference/statements/select/order-by); в противном случае из-за многопоточности блоки строк не будут упорядочены). Затем ClickHouse применяет `LIMIT n BY expressions` и возвращает первые `n` строк для каждой уникальной комбинации `expressions`. Если указан `OFFSET`, то для каждого блока данных, относящегося к отдельной комбинации `expressions`, ClickHouse пропускает `offset_value` строк с начала блока и возвращает в результате не более `n` строк. Если `offset_value` превышает число строк в блоке данных, ClickHouse не возвращает из этого блока ни одной строки.

<Note>
  `LIMIT BY` не связан с [LIMIT](/ru/reference/statements/select/limit). Оба можно использовать в одном и том же запросе.
</Note>

Если вы хотите использовать номера столбцов вместо имен столбцов в предложении `LIMIT BY`, включите настройку [enable\_positional\_arguments](/ru/reference/settings/session-settings#enable_positional_arguments).

<div id="examples">
  ## Примеры
</div>

Пример таблицы:

```sql theme={null}
CREATE TABLE limit_by(id Int, val Int) ENGINE = Memory;
INSERT INTO limit_by VALUES (1, 10), (1, 11), (1, 12), (2, 20), (2, 21);
```

Запросы:

```sql theme={null}
SELECT * FROM limit_by ORDER BY id, val LIMIT 2 BY id;
```

```text theme={null}
┌─id─┬─val─┐
│  1 │  10 │
│  1 │  11 │
│  2 │  20 │
│  2 │  21 │
└────┴─────┘
```

```sql theme={null}
SELECT * FROM limit_by ORDER BY id, val LIMIT 1, 2 BY id;
```

```text theme={null}
┌─id─┬─val─┐
│  1 │  11 │
│  1 │  12 │
│  2 │  21 │
└────┴─────┘
```

Запрос `SELECT * FROM limit_by ORDER BY id, val LIMIT 2 OFFSET 1 BY id` возвращает тот же результат.

Следующий запрос возвращает 5 лучших источников перехода для каждой пары `domain, device_type` при общем максимуме в 100 строк (`LIMIT n BY + LIMIT`).

```sql theme={null}
SELECT
    domainWithoutWWW(URL) AS domain,
    domainWithoutWWW(REFERRER_URL) AS referrer,
    device_type,
    count() cnt
FROM hits
GROUP BY domain, referrer, device_type
ORDER BY cnt DESC
LIMIT 5 BY domain, device_type
LIMIT 100;
```

`LIMIT BY` также поддерживает отрицательные лимиты и смещения. Как и в случае с [отрицательной командой LIMIT](/ru/reference/statements/select/limit#negative-limits), с `LIMIT BY` можно использовать отрицательные значения, чтобы выбирать строки с *конца* каждой группы.

```sql theme={null}
SELECT * FROM limit_by ORDER BY id, val LIMIT -2 BY id;
```

```text theme={null}
┌─id─┬─val─┐
│  1 │  11 │
│  1 │  12 │
│  2 │  20 │
│  2 │  21 │
└────┴─────┘
```

Возвращает последние 2 строки для каждого `id`. Для `id = 1` получаем строки `11` и `12`; для `id = 2` возвращаются обе строки, так как в группе всего 2 строки.

```sql theme={null}
SELECT * FROM limit_by ORDER BY id, val LIMIT -1 OFFSET -1 BY id;
```

```text theme={null}
┌─id─┬─val─┐
│  1 │  11 │
│  2 │  20 │
└────┴─────┘
```

Возвращает предпоследнюю строку для каждого `id`: завершающий `OFFSET -1` отбрасывает последнюю строку в каждой группе, а ведущий `-1` затем оставляет последнюю строку из оставшихся.

Также можно сочетать `LIMIT` и `OFFSET` с разными знаками. Например, чтобы отбросить первую строку каждой группы, а затем оставить последние 2 из оставшихся:

```sql theme={null}
SELECT * FROM limit_by ORDER BY id, val LIMIT -2 OFFSET 1 BY id;
```

```text theme={null}
┌─id─┬─val─┐
│  1 │  11 │
│  1 │  12 │
│  2 │  21 │
└────┴─────┘
```

Для `id = 1` первая строка (`10`) пропускается; возвращаются обе последние строки — `11` и `12`. Для `id = 2` первая строка (`20`) пропускается, остаётся только `21`.

<div id="limit-by-all">
  ## LIMIT BY ALL
</div>

`LIMIT BY ALL` эквивалентен перечислению всех выражений в `SELECT`, которые не являются агрегатными функциями.

Например:

```sql theme={null}
SELECT col1, col2, col3 FROM table LIMIT 2 BY ALL;
```

то же, что и

```sql theme={null}
SELECT col1, col2, col3 FROM table LIMIT 2 BY col1, col2, col3;
```

В особом случае, если среди аргументов функции есть как агрегатные функции, так и другие поля, ключи `LIMIT BY` будут включать максимально возможное количество неагрегатных полей, которые можно из неё извлечь.

Например:

```sql theme={null}
SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t LIMIT 2 BY ALL;
```

то же, что и

```sql theme={null}
SELECT substring(a, 4, 2), substring(substring(a, 1, 2), 1, count(b)) FROM t LIMIT 2 BY substring(a, 4, 2), substring(a, 1, 2);
```

<div id="examples">
  ## Примеры
</div>

Пример таблицы:

```sql theme={null}
CREATE TABLE limit_by(id Int, val Int) ENGINE = Memory;
INSERT INTO limit_by VALUES (1, 10), (1, 11), (1, 12), (2, 20), (2, 21);
```

Запросы:

```sql theme={null}
SELECT * FROM limit_by ORDER BY id, val LIMIT 2 BY id;
```

```text theme={null}
┌─id─┬─val─┐
│  1 │  10 │
│  1 │  11 │
│  2 │  20 │
│  2 │  21 │
└────┴─────┘
```

```sql theme={null}
SELECT * FROM limit_by ORDER BY id, val LIMIT 1, 2 BY id;
```

```text theme={null}
┌─id─┬─val─┐
│  1 │  11 │
│  1 │  12 │
│  2 │  21 │
└────┴─────┘
```

Запрос `SELECT * FROM limit_by ORDER BY id, val LIMIT 2 OFFSET 1 BY id` возвращает тот же результат.

С использованием `LIMIT BY ALL`:

```sql theme={null}
SELECT id, val FROM limit_by ORDER BY id, val LIMIT 2 BY ALL;
```

Это эквивалентно:

```sql theme={null}
SELECT id, val FROM limit_by ORDER BY id, val LIMIT 2 BY id, val;
```
