> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/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}
qc = client.create_query_context(
    query="SELECT {k:Int32}",
    parameters={"k": 13},
)
result = client.query(context=qc)
assert result.first_row == (13,)

qc.set_parameter("k", 79)
result = client.query(context=qc)
assert result.first_row == (79,)
```

Обратите внимание, что объекты `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 `RecordBatch`
* `query_df_arrow_stream` -- Возвращает каждый батч Arrow как DataFrame Pandas или Polars, выбранный с помощью `dataframe_library`

Каждый метод возвращает `StreamContext`, который необходимо открыть с помощью оператора `with`. Методы стриминга async client ожидаются через `await` и открываются с помощью `async with`.

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

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

* [max\_block\_size](/docs/ru/reference/settings/session-settings#max_block_size) -- Максимальный размер блока в строках.
* [preferred\_block\_size\_bytes](/docs/ru/reference/settings/session-settings#preferred_block_size_bytes) -- Предпочтительный размер блока в байтах.

Независимо от `preferred_block_size_bytes`, блок не будет превышать `max_block_size` строк. Фактический размер может быть меньше и не должен считаться стабильным.

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

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

Если приложение получает блоки значительно медленнее, чем сервер их отправляет, HTTP-соединение может закрыться до завершения обработки. Увеличьте значение общей настройки `http_buffer_size`, если у приложения достаточно памяти для буферизации большего объёма данных ответа. По умолчанию это значение равно 10 MiB. Данные ответа, сжатые с помощью 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:
            process_trip(row)
```

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

Если соединение прерывается во время чтения результата, вместо молчаливого возврата усечённого результата возникает `StreamFailureError`. Его сообщение соответствует настройке клиента `show_clickhouse_errors`.

Вы можете использовать свойство `source` объекта `StreamContext`, чтобы получить доступ к родительскому объекту результата, который содержит имена столбцов и типы. Для большинства потоков это `QueryResult`; методы `query_np_stream` и `query_df_stream` вместо этого возвращают `NumpyResult`.

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

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

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

Метод `query_rows_stream` автоматически переходит к следующему блоку и выдаёт по одной строке за раз. Это построчный аналог `query_row_block_stream`.

Метод `query_np_stream` возвращает каждый блок как массив NumPy. Когда все столбцы результата имеют общий NumPy dtype, массив является двумерным и имеет форму `(строки, столбцы)`. Смешанные результаты возвращаются как одномерный структурированный массив или используют dtype `object`.

Метод `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:
        process_dataframe(df)
```

Метод `query_df_arrow_stream` преобразует батчи Arrow в Pandas или Polars DataFrame. Выберите библиотеку с помощью `dataframe_library` (по умолчанию — `"pandas"`).

Наконец, метод `query_arrow_stream` оборачивает ответ ClickHouse `ArrowStream` в `StreamContext`. На каждой итерации возвращается PyArrow `RecordBatch`.

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

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

```python theme={null}
import clickhouse_connect

client = clickhouse_connect.get_client()

# Stream large result sets row by row
with client.query_rows_stream("SELECT number, number * 2 as doubled FROM system.numbers LIMIT 100000") as stream:
    for row in stream:
        print(row)  # Process each row
        # Output:
        # (0, 0)
        # (1, 2)
        # (2, 4)
        # Additional rows follow
```

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

```python theme={null}
import clickhouse_connect

client = clickhouse_connect.get_client()

# Stream in blocks of rows (more efficient than row-by-row)
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")
```

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

```python theme={null}
import clickhouse_connect

client = clickhouse_connect.get_client()

# Stream query results as Pandas DataFrames
with client.query_df_stream("SELECT number, toString(number) AS str FROM system.numbers LIMIT 100000") as stream:
    for df in stream:
        # Process each DataFrame block
        print(f"Received DataFrame with {len(df)} rows")
        print(df.head(3))
```

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

```python theme={null}
import clickhouse_connect

client = clickhouse_connect.get_client()

# Stream query results as Arrow record batches
with client.query_arrow_stream("SELECT * FROM large_table") as stream:
    for arrow_batch in stream:
        # Process each Arrow batch
        print(f"Received Arrow batch with {arrow_batch.num_rows} rows")
```

<div id="async-stream-rows">
  #### Асинхронный стриминг строк
</div>

```python theme={null}
import asyncio

import clickhouse_connect


async def main():
    async_client = await clickhouse_connect.get_async_client()
    async with await async_client.query_rows_stream(
        "SELECT number FROM numbers(100000)"
    ) as stream:
        async for row in stream:
            print(row)


asyncio.run(main())
```

<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()

# Query returns a NumPy array
np_array = client.query_np("SELECT number, number * 2 AS doubled FROM system.numbers LIMIT 5")

print(type(np_array))
# Output:
# <class 'numpy.ndarray'>

print(np_array)
# Output:
# [[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()

# Query returns a Pandas DataFrame
df = client.query_df("SELECT number, number * 2 AS doubled FROM system.numbers LIMIT 5")

print(type(df))
# Output: <class 'pandas.core.frame.DataFrame'>
print(df)
# Output:
#    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`, `parameters`, `settings`, `external_data` и `transport_settings`. Параметр `use_strings` определяет, будут ли столбцы ClickHouse `String` выводиться как строки Arrow или как двоичные значения.

```python theme={null}
import clickhouse_connect

client = clickhouse_connect.get_client()

# Query returns a PyArrow Table
arrow_table = client.query_arrow("SELECT number, toString(number) AS str FROM system.numbers LIMIT 3")

print(type(arrow_table))
# Output:
# <class 'pyarrow.lib.Table'>

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

<div id="arrow-backed-dataframes">
  ### DataFrames на базе Arrow
</div>

ClickHouse Connect поддерживает эффективное создание DataFrame из результатов в формате Arrow с помощью `query_df_arrow` и `query_df_arrow_stream`. Эти методы позволяют избежать преобразования через объекты строк в Python и повторно использовать буферы Arrow там, где это поддерживается целевой библиотекой:

* `query_df_arrow`: Выполняет запрос, используя выходной формат ClickHouse `Arrow`, и возвращает DataFrame.
  * `dataframe_library="pandas"` возвращает DataFrame Pandas 2.0 или более поздней версии с использованием `pd.ArrowDtype`.
  * `dataframe_library="polars"` возвращает DataFrame Polars, созданный с помощью `pl.from_arrow`.
* `query_df_arrow_stream`: Передаёт батчи Arrow в виде DataFrame Pandas или Polars.

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

```python theme={null}
import clickhouse_connect

client = clickhouse_connect.get_client()

# Query returns a Pandas DataFrame with Arrow dtypes (requires 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)
# Output:
# number    uint64[pyarrow]
# str       string[pyarrow]
# dtype: object

# Or use Polars
polars_df = client.query_df_arrow(
    "SELECT number, toString(number) AS str FROM system.numbers LIMIT 3",
    dataframe_library="polars"
)
print(polars_df.dtypes)
# Output:
# [UInt64, String]

# Streaming into batches of DataFrames (polars shown)
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}")
```

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

* ClickHouse определяет схему Arrow. Типы, для которых в Arrow нет прямого представления, могут возвращаться в совместимом физическом типе, включая двоичные поля. Проверяйте `table.schema` или dtypes DataFrame, прежде чем применять специфичные для приложения преобразования.
* Результаты Pandas на базе Arrow требуют Pandas 2.0 или более поздней версии.
* `use_strings` определяет, будут ли столбцы ClickHouse `String` использовать строковые или двоичные поля Arrow, если сервер поддерживает `output_format_arrow_string_as_string`.
* `tz_mode="schema"` пока не поддерживается методами запросов на базе Arrow. Они выдают предупреждение и сохраняют метаданные часового пояса, переданные в ответе Arrow.

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

Форматы чтения определяют значения, возвращаемые `query`, `query_np` и `query_df`. Они не применяются к методам raw или Arrow, поскольку эти методы напрямую используют формат вывода сервера. Например, если задать для UUID формат чтения `"string"`, будут возвращаться строки UUID, а не объекты `uuid.UUID`.

Аргумент "тип данных" для любой функции форматирования может включать подстановочные шаблоны. Формат задается одной строкой в нижнем регистре. Обертки-контейнеры, такие как `Array`, `Nullable` и `LowCardinality`, сохраняют выбранный формат для своего типа элементов.

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

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

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

# Return both IPv6 and IPv4 values as strings
set_read_format("IPv*", "string")

# Return all Date types as the underlying epoch second or epoch day
set_read_format("Date*", "int")
```

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

```python theme={null}
# Return any UUID column as a string
client.query(
    "SELECT user_id, user_uuid, device_uuid FROM users",
    query_formats={"UUID": "string"},
)
```

* Для отдельного столбца результата используйте необязательный словарь `column_formats`. Каждый ключ — это имя возвращаемого столбца. Его значение — строка формата или вложенное сопоставление имён типов ClickHouse с форматами, что полезно для Tuple, Map и других контейнерных типов.

```python theme={null}
# Return IPv6 values in the `dev_address` column as strings
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                     | string            |                                                                                                                               |
| UInt64                  | int                     | signed            | Superset пока не поддерживает большие беззнаковые значения UInt64                                                             |
| \[U]Int\[128,256]       | int                     | string            | Значения int в Pandas и NumPy ограничены 64 битами, поэтому они могут возвращаться как строки                                 |
| BFloat16                | float                   | -                 | Все значения float в Python внутри представлены 64 битами                                                                     |
| Float32                 | float                   | string            | Все значения float в Python внутри представлены 64 битами                                                                     |
| Float64                 | float                   | string            |                                                                                                                               |
| Decimal                 | decimal.Decimal         | -                 |                                                                                                                               |
| String                  | str                     | bytes             | Столбцы String в ClickHouse не имеют встроенного кодирования, поэтому также используются для бинарных данных переменной длины |
| FixedString             | bytes                   | string            | FixedString — это байтовые массивы фиксированного размера, но иногда они интерпретируются как строки Python                   |
| Enum\[8,16]             | str                     | int               | Нативный формат возвращает метки; `int` возвращает базовое целочисленное значение.                                            |
| Date                    | datetime.date           | int               | Целочисленный формат возвращает количество дней с 1970-01-01.                                                                 |
| Date32                  | datetime.date           | int               | Целочисленный формат возвращает расширенное знаковое смещение в днях.                                                         |
| DateTime                | datetime.datetime       | int               | Целочисленный формат возвращает секунды epoch.                                                                                |
| DateTime64              | datetime.datetime       | int               | Целочисленный формат возвращает ticks с точностью столбца. Python `datetime` ограничен микросекундами.                        |
| Time                    | datetime.timedelta      | int, string, time | Целочисленный формат возвращает секунды. Формат `time` ограничен значениями, которые помещаются в `datetime.time`.            |
| Time64                  | datetime.timedelta      | int, string, time | Целочисленный формат возвращает ticks с точностью столбца. Python `timedelta` ограничен микросекундами.                       |
| IPv4                    | `ipaddress.IPv4Address` | string, int       | IP-адреса можно читать как строки или целые числа.                                                                            |
| IPv6                    | `ipaddress.IPv6Address` | string            | IP-адреса можно читать как строки; при правильном форматировании их можно вставлять как IP-адреса                             |
| Tuple                   | dict or tuple           | tuple, dict, json | Именованные Tuple по умолчанию возвращают словари; неименованные Tuple возвращают кортежи.                                    |
| Map                     | dict                    | -                 |                                                                                                                               |
| Nested                  | Sequence\[dict]         | -                 |                                                                                                                               |
| UUID                    | uuid.UUID               | string            | UUID можно читать как строки, отформатированные в соответствии с RFC 4122<br />                                               |
| JSON                    | dict                    | string            | По умолчанию возвращается словарь Python. Формат `string` возвращает JSON-строку                                              |
| Variant                 | object                  | typed             | `typed` возвращает `TypedVariant(value, type_name)`, чтобы сохранить исходный тип элемента.                                   |
| Dynamic                 | object                  | -                 | Возвращает соответствующий тип Python для типа данных ClickHouse, хранящегося в значении                                      |
| QBit                    | list\[float]            | -                 | Если установлен NumPy, он автоматически используется для более быстрого транспонирования битов.                               |

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

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

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

В этом примере внешний CSV-файл объединяется через JOIN с таблицей `directors`, хранящейся на сервере:

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

backend chDB не поддерживает внешние данные.

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

Значения ClickHouse `DateTime` и `DateTime64` передаются как числовые значения на основе epoch. ClickHouse Connect преобразует их в объекты Python `datetime`, используя метаданные столбцов, переопределения запроса и политику часовых поясов клиента.

У клиента есть два независимых параметра часового пояса:

* `tz_source` задаёт резервный часовой пояс для столбцов без явных метаданных часового пояса:
  * `"auto"` используется по умолчанию. В этом режиме используется часовой пояс сервера, если клиент может надёжно определить его с учётом переходов на летнее время; в противном случае используется локальный часовой пояс.
  * `"server"` всегда использует часовой пояс сервера.
  * `"local"` всегда использует локальный часовой пояс процесса.
* `tz_mode` управляет учётом часового пояса:
  * `"naive_utc"` используется по умолчанию. Результаты в UTC и эквивалентных UTC часовых поясах возвращаются как naive-объекты `datetime` для обратной совместимости.
  * `"aware"` сохраняет `tzinfo` UTC и возвращает UTC-значения с информацией о часовом поясе.
  * `"schema"` возвращает значения с информацией о часовом поясе только в том случае, если тип столбца объявляет часовой пояс, и naive-значения для обычных столбцов `DateTime`/`DateTime64`.

Для обычных запросов с `"naive_utc"` и `"aware"` активный часовой пояс выбирается в следующем порядке:

1. Переопределение `column_tzs` для отдельного столбца.
2. Метаданные часового пояса в типе столбца ClickHouse.
3. Переопределение `query_tz` для всего запроса.
4. Информация о часовом поясе, возвращённая в HTTP-ответе.
5. Резервный часовой пояс, выбранный через `tz_source`.

`tz_mode="schema"` игнорирует часовые пояса запроса и резервные часовые пояса, но явное переопределение `column_tzs` по-прежнему имеет приоритет.

```python theme={null}
result = client.query(
    "SELECT "
    "toDateTime('2026-01-15 12:00:00', 'UTC') AS utc_time, "
    "toDateTime('2026-01-15 12:00:00', 'America/Denver') AS denver_time",
    tz_mode="aware",
)

assert result.first_row[0].tzinfo is not None
assert result.first_row[1].tzinfo is not None
```

Названия часовых поясов обрабатываются стандартным модулем библиотеки `zoneinfo`. В Windows `tzdata` устанавливается автоматически. В минимальных Linux-образах без базы часовых поясов IANA установите `clickhouse-connect[tzdata]`.

Результаты Pandas сохраняют естественную точность каждого типа ClickHouse, например `datetime64[s]` для `DateTime` и `datetime64[ms]` для `DateTime64(3)`. Методы DataFrame на базе Arrow `query_df_arrow` и `query_df_arrow_stream` пока не поддерживают `tz_mode="schema"` и выдают предупреждение, если запрошен этот режим. `query_arrow` и `query_arrow_stream` возвращают метаданные часового пояса из ответа Arrow без изменений.
