> ## 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.

> Продвинутые запросы с ClickHouse Connect

# Продвинутые запросы

<div id="querycontexts">
  ## QueryContexts
</div>

ClickHouse Connect выполняет стандартные запросы в контексте `QueryContext`. `QueryContext` содержит ключевые структуры, используемые для построения запросов к базе данных ClickHouse, а также конфигурацию, которая используется для преобразования результата в `QueryResult` или другую структуру данных ответа. Сюда входят сам запрос, параметры, настройки, форматы чтения и другие свойства.

`QueryContext` можно получить с помощью клиентского метода `create_query_context`. Этот метод принимает те же параметры, что и основной метод запроса. Затем этот контекст можно передать в методы `query`, `query_df` или `query_np` как именованный аргумент `context` вместо части или всех остальных аргументов этих методов. Обратите внимание, что дополнительные аргументы, указанные при вызове метода, переопределяют любые свойства `QueryContext`.

Наиболее понятный сценарий использования `QueryContext` — отправка одного и того же запроса с разными значениями параметров привязки. Все значения параметров можно обновить, вызвав метод `QueryContext.set_parameters` и передав ему словарь, а любое отдельное значение — вызвав `QueryContext.set_parameter` с нужной парой `key`, `value`.

```python theme={null}
client.create_query_context(query='SELECT value1, value2 FROM data_table WHERE key = {k:Int32}',
                            parameters={'k': 2},
                            column_oriented=True)
result = client.query(context=qc)
assert result.result_set[1][0] == 'second_value2'
qc.set_parameter('k', 1)
result = test_client.query(context=qc)
assert result.result_set[1][0] == 'first_value2'
```

Обратите внимание, что объекты `QueryContext` не являются потокобезопасными, однако в многопоточной среде можно получить их копию, вызвав метод `QueryContext.updated_copy`.

<div id="streaming-queries">
  ## Стриминг запросов
</div>

Клиент ClickHouse Connect предоставляет несколько методов для получения данных в виде потока (реализованного как генератор Python):

* `query_column_block_stream` -- Возвращает данные запроса блоками как последовательность столбцов с использованием собственных объектов Python
* `query_row_block_stream` -- Возвращает данные запроса как блок строк с использованием собственных объектов Python
* `query_rows_stream` -- Возвращает данные запроса как последовательность строк с использованием собственных объектов Python
* `query_np_stream` -- Возвращает каждый блок данных запроса ClickHouse как массив NumPy
* `query_df_stream` -- Возвращает каждый блок данных запроса ClickHouse как DataFrame Pandas
* `query_arrow_stream` -- Возвращает данные запроса в виде PyArrow RecordBlocks
* `query_df_arrow_stream` -- Возвращает каждый блок данных запроса ClickHouse как DataFrame Pandas на базе Arrow или как DataFrame Polars в зависимости от аргумента `dataframe_library` (по умолчанию — "pandas").

Каждый из этих методов возвращает объект `ContextStream`, который необходимо открыть с помощью оператора `with`, чтобы начать чтение потока.

<div id="data-blocks">
  ### Блоки данных
</div>

ClickHouse Connect обрабатывает все данные из основного метода `query` как поток блоков, получаемых от сервер ClickHouse. Эти блоки передаются в собственном формате "Native" в ClickHouse и из ClickHouse. «Блок» — это просто последовательность столбцов бинарных данных, где каждый столбец содержит одинаковое количество значений указанного типа данных. (Поскольку ClickHouse — колоночная база данных, он хранит эти данные в похожем виде.) Размер блока, возвращаемого запросом, определяется двумя пользовательскими настройками, которые можно задавать на нескольких уровнях (профиль пользователя, пользователь, сеанс или запрос). Вот они:

* [max\_block\_size](/ru/reference/settings/session-settings#max_block_size) -- Ограничение на размер блока в строках. По умолчанию — 65536.
* [preferred\_block\_size\_bytes](/ru/reference/settings/session-settings#preferred_block_size_bytes) -- Мягкое ограничение на размер блока в байтах. По умолчанию — 1,000,0000.

Независимо от `preferred_block_size_setting`, каждый блок никогда не будет содержать более `max_block_size` строк. В зависимости от типа запроса фактически возвращаемые блоки могут быть любого размера. Например, запросы к distributed таблице, охватывающей много сегментов, могут содержать блоки меньшего размера, полученные напрямую из каждого сегмента.

При использовании одного из методов клиента `query_*_stream` результаты возвращаются по блокам. ClickHouse Connect загружает только один блок за раз. Это позволяет обрабатывать большие объёмы данных без необходимости загружать в память весь большой результирующий набор. Обратите внимание: приложение должно быть готово обработать любое количество блоков, а точный размер каждого блока нельзя контролировать.

<div id="http-data-buffer-for-slow-processing">
  ### HTTP-буфер данных для медленной обработки
</div>

Из-за ограничений HTTP-протокола, если блоки обрабатываются со скоростью, значительно ниже той, с которой сервер ClickHouse передает данные в потоковом режиме, сервер ClickHouse закроет соединение, и в потоке обработки будет сгенерировано исключение. Частично эту проблему можно смягчить, увеличив размер буфера для потоковой передачи по HTTP (по умолчанию 10 мегабайт) с помощью общей настройки `http_buffer_size`. В этой ситуации большие значения `http_buffer_size` допустимы, если приложению доступно достаточно памяти. Данные в буфере хранятся в сжатом виде при использовании сжатия `lz4` или `zstd`, поэтому эти типы сжатия увеличивают общий доступный размер буфера.

<div id="streamcontexts">
  ### StreamContexts
</div>

Каждый из методов `query_*_stream` (например, `query_row_block_stream`) возвращает объект ClickHouse `StreamContext`, который сочетает в себе Python-контекст и генератор. Вот базовое использование:

```python theme={null}
with client.query_row_block_stream('SELECT pickup, dropoff, pickup_longitude, pickup_latitude FROM taxi_trips') as stream:
    for block in stream:
        for row in block:
            <выполнить действие с каждой строкой данных о поездке на Python>
```

Обратите внимание: попытка использовать `StreamContext` без оператора `with` вызовет ошибку. Использование контекста Python гарантирует, что поток (в данном случае — потоковый HTTP-ответ) будет корректно закрыт, даже если будут прочитаны не все данные и/или в ходе обработки возникнет исключение. Кроме того, `StreamContext` можно использовать для чтения потока только один раз. Попытка использовать `StreamContext` после выхода из него приведёт к ошибке `StreamClosedError`.

Вы можете использовать свойство `source` объекта `StreamContext`, чтобы получить доступ к родительскому объекту `QueryResult`, который содержит имена столбцов и типы.

<div id="stream-types">
  ### Типы потоков
</div>

Метод `query_column_block_stream` возвращает блок как последовательность данных столбцов в нативных типах данных Python. Если использовать приведённые выше запросы `taxi_trips`, возвращённые данные будут представлять собой список, где каждый элемент — это ещё один список (или кортеж), содержащий все данные соответствующего столбца. То есть `block[0]` будет кортежем, содержащим только строковые значения. Форматы с ориентацией по столбцам чаще всего используются для выполнения агрегатных операций над всеми значениями в столбце, например для подсчёта общей стоимости поездок.

Метод `query_row_block_stream` возвращает блок как последовательность строк, как в традиционной реляционной базе данных. Для поездок на такси возвращённые данные будут представлять собой список, где каждый элемент — это ещё один список, представляющий строку данных. То есть `block[0]` будет содержать все поля (по порядку) для первой поездки на такси, `block[1]` — строку со всеми полями второй поездки на такси, и так далее. Результаты с ориентацией по строкам обычно используются для отображения или преобразования данных.

`query_row_stream` — это вспомогательный метод, который автоматически переходит к следующему блоку при итерации по потоку. В остальном он идентичен `query_row_block_stream`.

Метод `query_np_stream` возвращает каждый блок как двумерный массив NumPy. Внутри массивы NumPy (как правило) хранятся по столбцам, поэтому отдельные методы для строк и столбцов не нужны. «Форма» массива NumPy будет выражена как (столбцы, строки). Библиотека NumPy предоставляет множество методов для работы с массивами NumPy. Обратите внимание: если все столбцы в запросе имеют один и тот же NumPy dtype, то и возвращённый массив NumPy тоже будет иметь только один dtype, и его можно будет переупорядочивать по форме/поворачивать без фактического изменения его внутренней структуры.

Метод `query_df_stream` возвращает каждый блок ClickHouse как двумерный Pandas DataFrame. Ниже приведён пример, показывающий, что объект `StreamContext` можно использовать как контекстный менеджер в отложенном режиме (но только один раз).

```python theme={null}
df_stream = client.query_df_stream('SELECT * FROM hits')
column_names = df_stream.source.column_names
with df_stream:
    for df in df_stream:
        <do something with the pandas DataFrame>
```

Метод `query_df_arrow_stream` возвращает каждый блок ClickHouse в виде DataFrame с dtype-бэкендом PyArrow. Этот метод поддерживает DataFrame как в Pandas (2.x и выше), так и в Polars через параметр `dataframe_library` (по умолчанию — `"pandas"`). На каждой итерации выдаётся DataFrame, преобразованный из record batch PyArrow, что обеспечивает более высокую производительность и более эффективное использование памяти для некоторых типов данных.

Наконец, метод `query_arrow_stream` возвращает результат ClickHouse в формате `ArrowStream` в виде `pyarrow.ipc.RecordBatchStreamReader`, обёрнутого в `StreamContext`. На каждой итерации потока возвращается PyArrow RecordBlock.

<div id="streaming-examples">
  ### Примеры стриминга
</div>

<div id="stream-rows">
  #### Поток строк
</div>

```python theme={null}
import clickhouse_connect

client = clickhouse_connect.get_client()

# Потоковая передача больших результирующих наборов строка за строкой
with client.query_rows_stream("SELECT number, number * 2 as doubled FROM system.numbers LIMIT 100000") as stream:
    for row in stream:
        print(row)  # Обработка каждой строки
        # Вывод:
        # (0, 0)
        # (1, 2)
        # (2, 4)
        # ....
```

<div id="stream-row-blocks">
  #### Потоковая передача блоков со строками
</div>

```python theme={null}
import clickhouse_connect

client = clickhouse_connect.get_client()

# Потоковая передача блоками строк (эффективнее, чем построчная)
with client.query_row_block_stream("SELECT number, number * 2 FROM system.numbers LIMIT 100000") as stream:
    for block in stream:
        print(f"Received block with {len(block)} rows")
        # Вывод:
        # Получен блок из 65409 строк
        # Получен блок из 34591 строк
```

<div id="stream-pandas-dataframes">
  #### Потоковая передача Pandas DataFrame
</div>

```python theme={null}
import clickhouse_connect

client = clickhouse_connect.get_client()

# Потоковая передача результатов запроса в виде Pandas DataFrame
with client.query_df_stream("SELECT number, toString(number) AS str FROM system.numbers LIMIT 100000") as stream:
    for df in stream:
        # Обработка каждого блока DataFrame
        print(f"Received DataFrame with {len(df)} rows")
        print(df.head(3))
        # Вывод:
        # Получен DataFrame с 65409 строками
        #    number str
        # 0       0   0
        # 1       1   1
        # 2       2   2
        # Получен DataFrame с 34591 строками
        #    number    str
        # 0   65409  65409
        # 1   65410  65410
        # 2   65411  65411
```

<div id="stream-arrow-batches">
  #### Потоковая передача батчей Arrow
</div>

```python theme={null}
import clickhouse_connect

client = clickhouse_connect.get_client()

# Потоковая передача результатов запроса в виде батчей записей Arrow
with client.query_arrow_stream("SELECT * FROM large_table") as stream:
    for arrow_batch in stream:
        # Обработка каждого батча Arrow
        print(f"Received Arrow batch with {arrow_batch.num_rows} rows")
        # Вывод:
        # Получен батч Arrow с 65409 строками
        # Получен батч Arrow с 34591 строкой
```

<div id="numpy-pandas-and-arrow-queries">
  ## Запросы NumPy, Pandas и Arrow
</div>

ClickHouse Connect предоставляет специализированные методы для работы со структурами данных NumPy, Pandas и Arrow. Эти методы позволяют получать результаты запроса напрямую в этих популярных форматах данных без ручного преобразования.

<div id="numpy-queries">
  ### Запросы NumPy
</div>

Метод `query_np` возвращает результаты запроса в виде массива NumPy, а не объекта ClickHouse Connect `QueryResult`.

```python theme={null}
import clickhouse_connect

client = clickhouse_connect.get_client()

# Запрос возвращает массив NumPy
np_array = client.query_np("SELECT number, number * 2 AS doubled FROM system.numbers LIMIT 5")

print(type(np_array))
# Вывод:
# <class "numpy.ndarray">

print(np_array)
# Вывод:
# [[0 0]
#  [1 2]
#  [2 4]
#  [3 6]
#  [4 8]]
```

<div id="pandas-queries">
  ### Запросы Pandas
</div>

Метод `query_df` возвращает результаты запроса в виде объекта Pandas DataFrame, а не ClickHouse Connect `QueryResult`.

```python theme={null}
import clickhouse_connect

client = clickhouse_connect.get_client()

# Запрос возвращает Pandas DataFrame
df = client.query_df("SELECT number, number * 2 AS doubled FROM system.numbers LIMIT 5")

print(type(df))
# Вывод: <class "pandas.core.frame.DataFrame">
print(df)
# Вывод:
#    number  doubled
# 0       0        0
# 1       1        2
# 2       2        4
# 3       3        6
# 4       4        8
```

<div id="pyarrow-queries">
  ### Запросы PyArrow
</div>

Метод `query_arrow` возвращает результаты запроса в виде таблицы PyArrow. Он напрямую использует формат ClickHouse `Arrow`, поэтому из аргументов основного метода `query` поддерживает только три: `query`, `parameters` и `settings`. Кроме того, есть дополнительный аргумент `use_strings`, который определяет, будут ли типы ClickHouse String в таблице Arrow представлены как строки (если True) или как байты (если False).

```python theme={null}
import clickhouse_connect

client = clickhouse_connect.get_client()

# Запрос возвращает таблицу PyArrow
arrow_table = client.query_arrow("SELECT number, toString(number) AS str FROM system.numbers LIMIT 3")

print(type(arrow_table))
# Вывод:
# <class "pyarrow.lib.Table">

print(arrow_table)
# Вывод:
# pyarrow.Table
# number: uint64 not null
# str: string not null
# ----
# number: [[0,1,2]]
# str: [["0","1","2"]]
```

<div id="arrow-backed-dataframes">
  ### DataFrame на основе Arrow
</div>

ClickHouse Connect поддерживает быстрое и экономное по памяти создание `DataFrame` из результатов Arrow с помощью методов `query_df_arrow` и `query_df_arrow_stream`. Это тонкие обёртки над методами Arrow-запросов, которые по возможности выполняют преобразование в `DataFrame` без копирования:

* `query_df_arrow`: Выполняет запрос, используя выходной формат ClickHouse `Arrow`, и возвращает `DataFrame`.
  * Для `dataframe_library='pandas'` возвращает `DataFrame` pandas 2.x с типами данных на основе Arrow (`pd.ArrowDtype`). Для этого требуется pandas 2.x; где возможно, используются буферы без копирования, что обеспечивает высокую производительность и низкие накладные расходы по памяти.
  * Для `dataframe_library='polars'` возвращает `DataFrame` Polars, созданный из таблицы Arrow (`pl.from_arrow`); он также работает эффективно и в зависимости от данных может не требовать копирования.
* `query_df_arrow_stream`: Передаёт результаты потоком как последовательность `DataFrame` (pandas 2.x или Polars), преобразованных из батчей потока Arrow.

<div id="query-to-arrow-backed-dataframe">
  #### Запрос к DataFrame на базе Arrow
</div>

```python theme={null}
import clickhouse_connect

client = clickhouse_connect.get_client()

# Запрос возвращает Pandas DataFrame с типами Arrow (требуется pandas 2.x)
df = client.query_df_arrow(
    "SELECT number, toString(number) AS str FROM system.numbers LIMIT 3",
    dataframe_library="pandas"
)

print(df.dtypes)
# Вывод:
# number    uint64[pyarrow]
# str       string[pyarrow]
# dtype: object

# Или используйте Polars
polars_df = client.query_df_arrow(
    "SELECT number, toString(number) AS str FROM system.numbers LIMIT 3",
    dataframe_library="polars"
)
print(df.dtypes)
# Вывод:
# [UInt64, String]

# Потоковая передача батчами DataFrames (показано для polars)
with client.query_df_arrow_stream(
    "SELECT number, toString(number) AS str FROM system.numbers LIMIT 100000", dataframe_library="polars"
) as stream:
    for df_batch in stream:
        print(f"Received {type(df_batch)} batch with {len(df_batch)} rows and dtypes: {df_batch.dtypes}")
        # Вывод:
        # Received <class 'polars.dataframe.frame.DataFrame'> batch with 65409 rows and dtypes: [UInt64, String]
        # Received <class 'polars.dataframe.frame.DataFrame'> batch with 34591 rows and dtypes: [UInt64, String]
```

<div id="notes-and-caveats">
  #### Примечания и ограничения
</div>

* Сопоставление типов Arrow: при возврате данных в формате Arrow ClickHouse сопоставляет типы с ближайшими поддерживаемыми типами Arrow. Для некоторых типов ClickHouse нет прямого эквивалента в Arrow, поэтому они возвращаются как необработанные байты в полях Arrow (обычно `BINARY` или `FIXED_SIZE_BINARY`).
  * Примеры: `IPv4` представляется как Arrow `UINT32`; `IPv6` и большие целые числа (`Int128/UInt128/Int256/UInt256`) часто представляются как `FIXED_SIZE_BINARY`/`BINARY` с необработанными байтами.
  * В таких случаях столбец DataFrame будет содержать байтовые значения из поля Arrow; интерпретация или преобразование этих байтов в соответствии с семантикой ClickHouse выполняется на стороне клиентского кода.
* Неподдерживаемые типы данных Arrow (например, UUID/ENUM как полноценные типы Arrow) не выводятся; при выводе значения представляются с использованием ближайшего поддерживаемого типа Arrow (часто в виде бинарных байтов).
* Требование Pandas: типы данных на базе Arrow требуют pandas 2.x. Для более старых версий pandas используйте `query_df` (без Arrow).
* Строки и двоичные данные: параметр `use_strings` (если он поддерживается настройкой сервера `output_format_arrow_string_as_string`) определяет, будут ли столбцы ClickHouse `String` возвращаться как строки Arrow или как двоичные данные.

<div id="mismatched-clickhousearrow-type-conversion-examples">
  #### Примеры преобразования типов ClickHouse/Arrow при несовпадении
</div>

Когда ClickHouse возвращает столбцы в виде необработанных бинарных данных (например, `FIXED_SIZE_BINARY` или `BINARY`), преобразование этих байтов в подходящие типы Python выполняет прикладной код. Примеры ниже показывают, что некоторые преобразования удобно выполнять через API библиотеки DataFrame, тогда как в других случаях могут понадобиться чисто Python-решения, такие как `struct.unpack` (они уступают в производительности, но сохраняют гибкость).

Столбцы `Date` могут приходить как `UINT16` (число дней с эпохи Unix, 1970‑01‑01). Преобразование внутри DataFrame эффективно и выполняется просто:

```python theme={null}
# Polars
df = df.with_columns(pl.col("event_date").cast(pl.Date))

# Pandas
df["event_date"] = pd.to_datetime(df["event_date"], unit="D")
```

Столбцы типа `Int128` могут поступать в виде `FIXED_SIZE_BINARY` с сырыми байтами. Polars нативно поддерживает 128-битные целые числа:

```python theme={null}
# Polars — встроенная поддержка
df = df.with_columns(pl.col("data").bin.reinterpret(dtype=pl.Int128, endianness="little"))
```

Начиная с NumPy 2.3, публичного `dtype` для 128-битных целых чисел нет, поэтому приходится использовать чистый Python — например, так:

```python theme={null}
# Предполагаем, что у нас есть pandas dataframe со столбцом Int128 типа fixed_size_binary[16][pyarrow]

print(df)
# Вывод:
#   str_col                                        int_128_col
# 0    num1  b'\\x15}\\xda\\xeb\\x18ZU\\x0fn\\x05\\x01\\x00\\x00\\x00...
# 1    num2  b'\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00...
# 2    num3  b'\\x15\\xdfp\\x81r\\x9f\\x01\\x00\\x00\\x00\\x00\\x00\\x...

print([int.from_bytes(n, byteorder="little") for n in df["int_128_col"].to_list()])
# Вывод:
# [1234567898765432123456789, 8, 456789123456789]
```

Главный вывод: прикладной код должен выполнять эти преобразования с учетом возможностей выбранной библиотеки DataFrame и допустимых компромиссов в производительности. Если преобразования, встроенные в DataFrame, недоступны, можно использовать подходы на чистом Python.

<div id="read-formats">
  ## Форматы чтения
</div>

Форматы чтения определяют типы данных значений, возвращаемых методами клиента `query`, `query_np` и `query_df`. (`raw_query` и `query_arrow` не изменяют данные, поступающие из ClickHouse, поэтому управление форматами к ним не применяется.) Например, если формат чтения для UUID изменён со стандартного формата `native` на альтернативный `string`, значения столбца `UUID` в результате запроса к ClickHouse будут возвращаться как строки (в стандартном формате RFC 1422 8-4-4-4-12), а не как объекты Python UUID.

Аргумент "тип данных" для любой функции форматирования может включать подстановочные шаблоны. Формат представляет собой одну строку в нижнем регистре.

Форматы чтения можно задавать на нескольких уровнях:

* Глобально, с помощью методов, определённых в пакете `clickhouse_connect.datatypes.format`. Это будет задавать формат для настроенного типа данных во всех запросах.

```python theme={null}
from clickhouse_connect.datatypes.format import set_read_format

# Возвращать значения IPv6 и IPv4 в виде строк
set_read_format('IPv*', 'string')

# Возвращать все типы Date как количество секунд или дней от начала эпохи
set_read_format('Date*', 'int')
```

* Для всего запроса — с использованием необязательного аргумента словаря `query_formats`. В этом случае любой столбец (или подстолбец) указанных типов данных будет использовать заданный формат.

```python theme={null}
# Вернуть любой столбец UUID в виде строки
client.query('SELECT user_id, user_uuid, device_uuid from users', query_formats={'UUID': 'string'})
```

* Для значений в конкретном столбце — с использованием необязательного аргумента словаря `column_formats`. Ключом служит имя столбца в том виде, в котором его возвращает ClickHouse, а значением — формат для столбца данных или вложенный словарь второго уровня "format", где ключом является имя типа ClickHouse, а значением — форматы запроса. Этот вторичный словарь можно использовать для вложенных типов столбцов, таких как Tuples или Maps.

```python theme={null}
# Возвращать значения IPv6 в столбце `dev_address` в виде строк
client.query('SELECT device_id, dev_address, gw_address from devices', column_formats={'dev_address':'string'})
```

<div id="read-format-options-python-types">
  ### Параметры формата чтения (типы Python)
</div>

| Тип ClickHouse          | Нативный тип Python     | Форматы чтения    | Комментарии                                                                                                                      |
| ----------------------- | ----------------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| Int\[8-64], UInt\[8-32] | int                     | -                 |                                                                                                                                  |
| UInt64                  | int                     | signed            | В настоящее время Superset не обрабатывает большие беззнаковые значения UInt64                                                   |
| \[U]Int\[128,256]       | int                     | string            | Значения int в Pandas и NumPy ограничены 64 битами, поэтому они могут возвращаться как строки                                    |
| BFloat16                | float                   | -                 | Все значения float в Python внутренне являются 64-битными                                                                        |
| Float32                 | float                   | -                 | Все значения float в Python внутренне являются 64-битными                                                                        |
| Float64                 | float                   | -                 |                                                                                                                                  |
| Decimal                 | decimal.Decimal         | -                 |                                                                                                                                  |
| String                  | string                  | bytes             | У столбцов String в ClickHouse нет встроенной кодировки, поэтому они также используются для двоичных данных переменной длины     |
| FixedString             | bytes                   | string            | FixedString — это массивы байтов фиксированного размера, но иногда они интерпретируются как строки Python                        |
| Enum\[8,16]             | string                  | string, int       | Перечисления Python не поддерживают пустые строки, поэтому все enum возвращаются либо как строки, либо как базовые значения int. |
| Date                    | datetime.date           | int               | ClickHouse хранит Date как количество дней с 01/01/1970. Это значение доступно как int                                           |
| Date32                  | datetime.date           | int               | То же, что и Date, но для более широкого диапазона дат                                                                           |
| DateTime                | datetime.datetime       | int               | ClickHouse хранит DateTime как количество секунд с начала epoch. Это значение доступно как int                                   |
| DateTime64              | datetime.datetime       | int               | Точность Python datetime.datetime ограничена микросекундами. Доступно исходное 64-битное значение int                            |
| Time                    | datetime.timedelta      | int, string, time | Момент времени сохраняется как Unix-временная метка. Это значение доступно как int                                               |
| Time64                  | datetime.timedelta      | int, string, time | Точность Python datetime.timedelta ограничена микросекундами. Доступно исходное 64-битное значение int                           |
| IPv4                    | `ipaddress.IPv4Address` | string            | IP-адреса можно читать как строки, а строки в корректном формате — вставлять как IP-адреса                                       |
| IPv6                    | `ipaddress.IPv6Address` | string            | IP-адреса можно читать как строки, а строки в корректном формате — вставлять как IP-адреса                                       |
| Tuple                   | dict or tuple           | tuple, json       | Именованные кортежи по умолчанию возвращаются как словари. Именованные кортежи также могут возвращаться как строки JSON          |
| Map                     | dict                    | -                 |                                                                                                                                  |
| Nested                  | Sequence\[dict]         | -                 |                                                                                                                                  |
| UUID                    | uuid.UUID               | string            | UUID можно читать как строки, отформатированные в соответствии с RFC 4122<br />                                                  |
| JSON                    | dict                    | string            | По умолчанию возвращается словарь Python. Формат `string` возвращает строку JSON                                                 |
| Variant                 | object                  | -                 | Возвращает соответствующий тип Python для типа данных ClickHouse, в котором хранится значение                                    |
| Dynamic                 | object                  | -                 | Возвращает соответствующий тип Python для типа данных ClickHouse, в котором хранится значение                                    |

<div id="external-data">
  ## Внешние данные
</div>

Запросы ClickHouse могут принимать внешние данные в любом формате ClickHouse. Эти двоичные данные отправляются вместе со строкой запроса и используются при обработке данных. Подробности о возможности External Data приведены [здесь](/ru/reference/engines/table-engines/special/external-data). Методы клиента `query*` принимают необязательный параметр `external_data`, позволяющий использовать эту возможность. Значением параметра `external_data` должен быть объект `clickhouse_connect.driver.external.ExternalData`. Конструктор этого объекта принимает следующие аргументы:

| Имя        | Тип               | Описание                                                                                                                                                     |
| ---------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| file\_path | str               | Путь к файлу в локальной файловой системе, из которого считываются внешние данные. Необходимо указать либо `file_path`, либо `data`                          |
| file\_name | str               | Имя "файла" внешних данных. Если не указано, будет определено по `file_path` (без расширения)                                                                |
| data       | bytes             | Внешние данные в двоичной форме (вместо чтения из файла). Необходимо указать либо `data`, либо `file_path`                                                   |
| fmt        | str               | [Входной формат](/ru/reference/formats) ClickHouse для данных. По умолчанию используется `TSV`                                                               |
| types      | str or seq of str | Список типов данных столбцов во внешних данных. Если передана строка, типы должны быть разделены запятыми. Необходимо указать либо `types`, либо `structure` |
| structure  | str or seq of str | Список имен столбцов и типов данных в данных (см. примеры). Необходимо указать либо `structure`, либо `types`                                                |
| mime\_type | str               | Необязательный MIME-тип данных файла. В настоящее время ClickHouse игнорирует этот HTTP-подзаголовок                                                         |

Чтобы отправить запрос с внешним CSV-файлом, содержащим данные о фильмах, и объединить эти данные с таблицей `directors`, уже существующей на сервере ClickHouse:

```python theme={null}
import clickhouse_connect
from clickhouse_connect.driver.external import ExternalData

client = clickhouse_connect.get_client()
ext_data = ExternalData(file_path='/data/movies.csv',
                        fmt='CSV',
                        structure=['movie String', 'year UInt16', 'rating Decimal32(3)', 'director String'])
result = client.query('SELECT name, avg(rating) FROM directors INNER JOIN movies ON directors.name = movies.director GROUP BY directors.name',
                      external_data=ext_data).result_rows
```

Дополнительные внешние файлы данных можно добавить в исходный объект `ExternalData` с помощью метода `add_file`, который принимает те же параметры, что и конструктор. При использовании HTTP все внешние данные передаются в составе загрузки файла `multi-part/form-data`.

<div id="time-zones">
  ## Часовые пояса
</div>

Существует несколько механизмов применения часового пояса к значениям ClickHouse DateTime и DateTime64. Внутренне сервер ClickHouse всегда хранит любой объект DateTime или `DateTime64` как число без привязки к часовому поясу, представляющее секунды с начала эпохи 1970-01-01 00:00:00 UTC. Для значений `DateTime64` представление может быть в миллисекундах, микросекундах или наносекундах с начала эпохи в зависимости от precision. В результате любая информация о часовом поясе всегда применяется на стороне клиента. Обратите внимание, что это требует дополнительных вычислений, поэтому в приложениях, критичных к производительности, рекомендуется рассматривать типы DateTime как временные метки эпохи, за исключением отображения для пользователя и преобразования (например, Pandas Timestamps всегда представляют собой 64-битное целое число, обозначающее наносекунды с начала эпохи, для повышения производительности).

При использовании в запросах типов данных с учетом часового пояса — в частности, объекта Python `datetime.datetime` -- `clickhouse-connect` применяет часовой пояс на стороне клиента по следующим правилам приоритета:

1. Если для запроса указан parameter метода `client_tzs`, применяется часовой пояс конкретного столбца
2. Если у столбца ClickHouse есть метаданные timezone (то есть это тип вроде DateTime64(3, 'America/Denver')), применяется часовой пояс столбца ClickHouse. (Обратите внимание, что эти метаданные timezone недоступны для clickhouse-connect для столбцов DateTime в версиях ClickHouse до 23.2)
3. Если для запроса указан parameter метода `query_tz`, применяется «часовой пояс запроса».
4. Если к запросу или сеансу применена настройка timezone, применяется этот часовой пояс. (Эта функциональность еще не выпущена в сервер ClickHouse)
5. Наконец, если parameter клиента `apply_server_timezone` установлен в True (по умолчанию), применяется часовой пояс сервер ClickHouse.

Обратите внимание, что если примененный по этим правилам часовой пояс — UTC, `clickhouse-connect` *всегда* вернет объект Python `datetime.datetime` без привязки к часовому поясу. При необходимости прикладной код затем может добавить к этому объекту дополнительную информацию о часовом поясе.
