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

> Consultas avanzadas con ClickHouse Connect

# Consultas avanzadas

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

ClickHouse Connect ejecuta consultas estándar dentro de un `QueryContext`. El `QueryContext` contiene las estructuras clave que se utilizan para crear consultas en la base de datos ClickHouse, así como la configuración usada para procesar el resultado en un `QueryResult` u otra estructura de datos de respuesta. Esto incluye la propia consulta, parámetros, ajustes, formatos de lectura y otras propiedades.

Se puede obtener un `QueryContext` mediante el método `create_query_context` del Client. Este método acepta los mismos parámetros que el método principal de consulta. Después, este contexto de consulta puede pasarse a los métodos `query`, `query_df` o `query_np` como argumento con nombre `context`, en lugar de cualquiera o de todos los demás argumentos de esos métodos. Tenga en cuenta que los argumentos adicionales especificados en la llamada al método sobrescribirán cualquier propiedad de `QueryContext`.

El caso de uso más claro de un `QueryContext` es enviar la misma consulta con distintos valores de parámetros enlazados. Todos los valores de los parámetros pueden actualizarse llamando al método `QueryContext.set_parameters` con un diccionario, o bien se puede actualizar un valor individual llamando a `QueryContext.set_parameter` con el par `key`, `value` deseado.

```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,)
```

Ten en cuenta que los `QueryContext`s no son seguros para su uso en varios hilos, pero se puede obtener una copia en un entorno multihilo llamando al método `QueryContext.updated_copy`.

<div id="streaming-queries">
  ## Consultas en streaming
</div>

El Client ClickHouse Connect proporciona varios métodos para recuperar datos como un stream (implementado como un generador de Python):

* `query_column_block_stream` -- Devuelve los datos de la consulta en bloques, como una secuencia de columnas, utilizando objetos nativos de Python
* `query_row_block_stream` -- Devuelve los datos de la consulta como un bloque de filas utilizando objetos nativos de Python
* `query_rows_stream` -- Devuelve los datos de la consulta como una secuencia de filas utilizando objetos nativos de Python
* `query_np_stream` -- Devuelve cada bloque de datos de la consulta de ClickHouse como un array de NumPy
* `query_df_stream` -- Devuelve cada bloque de datos de la consulta de ClickHouse como un DataFrame de Pandas
* `query_arrow_stream` -- Devuelve los datos de la consulta como objetos `RecordBatch` de PyArrow
* `query_df_arrow_stream` -- Devuelve cada lote de Arrow como un DataFrame de Pandas o de Polars, seleccionado por `dataframe_library`

Cada método devuelve un `StreamContext` que debe abrirse con una sentencia `with`. Los métodos de streaming del Client `async` deben esperarse y abrirse con `async with`.

<div id="data-blocks">
  ### Bloques de datos
</div>

ClickHouse Connect procesa todos los datos del método `query` principal como un flujo de bloques recibidos del servidor ClickHouse. Estos bloques se transmiten hacia y desde ClickHouse en el formato personalizado "Native". Un "bloque" es simplemente una secuencia de columnas de datos binarios, en la que cada columna contiene la misma cantidad de valores de datos del tipo de dato especificado. (Como base de datos columnar, ClickHouse almacena estos datos de forma similar). El tamaño de un bloque devuelto por una consulta depende de dos configuraciones de usuario que pueden establecerse en varios niveles (perfil de usuario, usuario, sesión o consulta). Son:

* [max\_block\_size](/es/reference/settings/session-settings#max_block_size) -- Tamaño máximo del bloque en filas.
* [preferred\_block\_size\_bytes](/es/reference/settings/session-settings#preferred_block_size_bytes) -- Tamaño preferido del bloque en bytes.

Independientemente de `preferred_block_size_bytes`, un bloque no superará `max_block_size` filas. El tamaño real puede ser menor y no debe considerarse estable.

Al usar uno de los métodos `query_*_stream` del cliente, los resultados se devuelven bloque por bloque. ClickHouse Connect solo carga un bloque a la vez. Esto permite procesar grandes cantidades de datos sin necesidad de cargar en memoria todo un conjunto de resultados grande. Ten en cuenta que la aplicación debe estar preparada para procesar cualquier cantidad de bloques y que el tamaño exacto de cada bloque no puede controlarse.

<div id="http-data-buffer-for-slow-processing">
  ### Búfer de datos HTTP para procesamiento lento
</div>

Si una aplicación consume bloques mucho más lentamente de lo que el servidor los produce, la conexión HTTP puede cerrarse antes de que termine el procesamiento. Aumente la configuración global `http_buffer_size` cuando la aplicación tenga suficiente memoria para almacenar en búfer más datos de respuesta. El valor predeterminado es de 10 MiB. Los bytes de respuesta de `lz4` y `zstd` permanecen comprimidos en este búfer, lo que aumenta su capacidad efectiva.

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

Cada uno de los métodos `query_*_stream` (como `query_row_block_stream`) devuelve un objeto `StreamContext` de ClickHouse, que combina un contexto y un generador de Python. Este es el uso básico:

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

Ten en cuenta que intentar usar un `StreamContext` sin una sentencia `with` generará un error. El uso de un contexto de Python garantiza que el stream (en este caso, una respuesta HTTP en streaming) se cierre correctamente aunque no se consuman todos los datos y/o se produzca una excepción durante el procesamiento. Además, los `StreamContext` solo pueden usarse una vez para consumir el stream. Intentar usar un `StreamContext` después de haber salido de él producirá un `StreamClosedError`.

Si la conexión falla mientras se está leyendo un resultado, se genera un `StreamFailureError` en lugar de devolver silenciosamente un resultado truncado. Su mensaje sigue la configuración `show_clickhouse_errors` del client.

Puedes usar la propiedad `source` del `StreamContext` para acceder al objeto de resultado padre, que incluye los nombres de las columnas y los tipos. Para la mayoría de los streams, este es un `QueryResult`; los métodos `query_np_stream` y `query_df_stream` exponen un `NumpyResult` en su lugar.

<div id="stream-types">
  ### Tipos de flujo
</div>

El método `query_column_block_stream` devuelve el bloque como una secuencia de datos de columna almacenados como tipos de datos nativos de Python. Si usamos las consultas `taxi_trips` anteriores, los datos devueltos serán una lista en la que cada elemento es otra lista (o tupla) que contiene todos los datos de la columna correspondiente. Así, `block[0]` sería una tupla que solo contendría cadenas. Los formatos orientados a columnas se usan sobre todo para realizar operaciones de agregación sobre todos los valores de una columna, como sumar las tarifas totales.

El método `query_row_block_stream` devuelve el bloque como una secuencia de filas, como en una base de datos relacional tradicional. Para los trayectos de taxi, los datos devueltos serán una lista en la que cada elemento es otra lista que representa una fila de datos. Así, `block[0]` contendría todos los campos (en orden) del primer trayecto de taxi, `block[1]` contendría una fila con todos los campos del segundo trayecto de taxi, y así sucesivamente. Los resultados orientados a filas normalmente se usan en procesos de visualización o transformación.

El método `query_rows_stream` pasa automáticamente al siguiente bloque y devuelve una fila cada vez. Es la contraparte fila por fila de `query_row_block_stream`.

El método `query_np_stream` devuelve cada bloque como un array de NumPy. Cuando todas las columnas del resultado comparten un `dtype` de NumPy, el array es bidimensional con forma `(filas, columnas)`. Los resultados mixtos se devuelven como un array estructurado unidimensional o usan el `dtype` `object`.

El método `query_df_stream` devuelve cada bloque de ClickHouse como un DataFrame de Pandas bidimensional. Aquí tienes un ejemplo que muestra que el objeto `StreamContext` puede usarse como contexto de forma diferida (pero solo una vez).

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

El método `query_df_arrow_stream` convierte lotes de Arrow en DataFrames de Pandas o Polars. Selecciona la biblioteca con `dataframe_library`, cuyo valor predeterminado es `"pandas"`.

Por último, `query_arrow_stream` encapsula una respuesta `ArrowStream` de ClickHouse en un `StreamContext`. Cada iteración devuelve un `RecordBatch` de PyArrow.

<div id="streaming-examples">
  ### Ejemplos de streaming
</div>

<div id="stream-rows">
  #### Transmitir filas en streaming
</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">
  #### Transmitir bloques de filas
</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">
  #### Transmitir DataFrames de Pandas
</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">
  #### Transmitir lotes de 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">
  #### Filas en streaming asíncrono
</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">
  ## Consultas con NumPy, Pandas y Arrow
</div>

ClickHouse Connect proporciona métodos de consulta especializados para trabajar con estructuras de datos de NumPy, Pandas y Arrow. Estos métodos le permiten obtener los resultados de las consultas directamente en estos formatos de datos populares, sin necesidad de conversión manual.

<div id="numpy-queries">
  ### Consultas con NumPy
</div>

El método `query_np` devuelve los resultados de la consulta como un array de NumPy en lugar de un `QueryResult` de ClickHouse Connect.

```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">
  ### Consultas con Pandas
</div>

El método `query_df` devuelve los resultados de la consulta como un DataFrame de Pandas en lugar de un `QueryResult` de ClickHouse Connect.

```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">
  ### Consultas con PyArrow
</div>

El método `query_arrow` devuelve una tabla de PyArrow utilizando directamente el formato de salida `Arrow` de ClickHouse. Acepta `query`, `parameters`, `settings`, `external_data` y `transport_settings`. La opción `use_strings` controla si las columnas `String` de ClickHouse se emiten como cadenas de Arrow o como valores binarios.

```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 basados en Arrow
</div>

ClickHouse Connect permite crear DataFrames de forma eficiente a partir de resultados de Arrow mediante `query_df_arrow` y `query_df_arrow_stream`. Estos métodos evitan la conversión mediante objetos fila de Python y reutilizan los búferes de Arrow cuando la biblioteca de destino lo permite:

* `query_df_arrow`: Ejecuta la consulta con el formato de salida `Arrow` de ClickHouse y devuelve un DataFrame.
  * `dataframe_library="pandas"` devuelve un DataFrame de Pandas 2.0 o posterior usando `pd.ArrowDtype`.
  * `dataframe_library="polars"` devuelve un DataFrame de Polars creado con `pl.from_arrow`.
* `query_df_arrow_stream`: Transmite lotes de Arrow como DataFrames de Pandas o Polars.

<div id="query-to-arrow-backed-dataframe">
  #### Consulta a un DataFrame basado en 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">
  #### Notas y advertencias
</div>

* ClickHouse controla el esquema de Arrow. Los tipos sin una representación directa en Arrow pueden devolverse usando un tipo físico compatible, incluidos los campos binarios. Inspeccione `table.schema` o los dtypes del DataFrame antes de aplicar conversiones específicas de la aplicación.
* Los resultados de Pandas basados en Arrow requieren Pandas 2.0 o posterior.
* `use_strings` controla si las columnas `String` de ClickHouse usan campos de cadena o binarios de Arrow cuando el servidor admite `output_format_arrow_string_as_string`.
* `tz_mode="schema"` todavía no es compatible con los métodos de consulta basados en Arrow. Emiten una advertencia y conservan los metadatos de zona horaria proporcionados por la respuesta de Arrow.

<div id="read-formats">
  ## Formatos de lectura
</div>

Los formatos de lectura controlan los valores devueltos por `query`, `query_np` y `query_df`. No se aplican a los métodos raw ni Arrow porque esos métodos usan directamente un formato de salida del servidor. Por ejemplo, establecer el formato de lectura de UUID en `"string"` devuelve cadenas UUID en lugar de objetos `uuid.UUID`.

El argumento "data type" de cualquier función de formatting puede incluir wildcards. El format es una única cadena en minúsculas. Los envoltorios de contenedor, como `Array`, `Nullable` y `LowCardinality`, conservan el formato seleccionado para su element type.

Los formatos de lectura pueden establecerse en varios niveles:

* Globalmente, usando los métodos definidos en el package `clickhouse_connect.datatypes.format`. Esto controlará el formato del tipo de dato configurado para todas las consultas.

```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")
```

* Para una consulta completa, con el argumento de diccionario opcional `query_formats`. En ese caso, cualquier columna (o subcolumna) de los tipos de dato especificados usará el formato configurado.

```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"},
)
```

* Para una columna de resultado específica, use el diccionario opcional `column_formats`. Cada clave es el nombre de una columna devuelta. Su valor es una cadena de formato o una correspondencia anidada entre nombres de tipos de ClickHouse y formatos, lo que resulta útil para Tuples, Maps y otros tipos contenedores.

```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">
  ### Opciones de formato de lectura (tipos de Python)
</div>

| Tipo de ClickHouse      | Tipo nativo de Python   | Formatos de lectura | Comentarios                                                                                                                                |
| ----------------------- | ----------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| Int\[8-64], UInt\[8-32] | int                     | string              |                                                                                                                                            |
| UInt64                  | int                     | signed              | Actualmente, Superset no admite valores UInt64 grandes sin signo                                                                           |
| \[U]Int\[128,256]       | int                     | string              | Los valores int de Pandas y NumPy tienen un máximo de 64 bits, por lo que pueden devolverse como cadenas                                   |
| BFloat16                | float                   | -                   | Todos los float de Python son internamente de 64 bits                                                                                      |
| Float32                 | float                   | string              | Todos los float de Python son internamente de 64 bits                                                                                      |
| Float64                 | float                   | string              |                                                                                                                                            |
| Decimal                 | decimal.Decimal         | -                   |                                                                                                                                            |
| String                  | str                     | bytes               | Las columna String de ClickHouse no tienen una codificación inherente, por lo que también se usan para datos binarios de longitud variable |
| FixedString             | bytes                   | string              | FixedStrings son arrays de bytes de tamaño fijo, pero a veces se tratan como cadenas de Python                                             |
| Enum\[8,16]             | str                     | int                 | El formato nativo devuelve etiquetas; `int` devuelve el entero subyacente.                                                                 |
| Date                    | datetime.date           | int                 | El formato entero devuelve los días desde 1970-01-01.                                                                                      |
| Date32                  | datetime.date           | int                 | El formato entero devuelve el desplazamiento ampliado de días con signo.                                                                   |
| DateTime                | datetime.datetime       | int                 | El formato entero devuelve segundos desde la época Unix.                                                                                   |
| DateTime64              | datetime.datetime       | int                 | El formato entero devuelve ticks con la precisión de la columna. `datetime` de Python está limitado a microsegundos.                       |
| Time                    | datetime.timedelta      | int, string, time   | El formato entero devuelve segundos. El formato `time` está limitado a valores que caben en `datetime.time`.                               |
| Time64                  | datetime.timedelta      | int, string, time   | El formato entero devuelve ticks con la precisión de la columna. `timedelta` de Python está limitado a microsegundos.                      |
| IPv4                    | `ipaddress.IPv4Address` | string, int         | Las direcciones IP pueden leerse como cadenas o enteros.                                                                                   |
| IPv6                    | `ipaddress.IPv6Address` | string              | Las direcciones IP pueden leerse como cadenas y, si tienen el formato adecuado, pueden insertarse como direcciones IP                      |
| Tuple                   | dict or tuple           | tuple, dict, json   | Las tuplas con nombre devuelven diccionarios de forma predeterminada; las tuplas sin nombre devuelven tuplas.                              |
| Map                     | dict                    | -                   |                                                                                                                                            |
| Nested                  | Sequence\[dict]         | -                   |                                                                                                                                            |
| UUID                    | uuid.UUID               | string              | Los UUIDs pueden leerse como cadenas con formato según RFC 4122<br />                                                                      |
| JSON                    | dict                    | string              | De forma predeterminada, se devuelve un diccionario de Python. El formato `string` devolverá una cadena JSON                               |
| Variant                 | object                  | typed               | `typed` devuelve `TypedVariant(value, type_name)` para preservar el tipo de miembro original.                                              |
| Dynamic                 | object                  | -                   | Devuelve el tipo de Python correspondiente al tipo de dato de ClickHouse almacenado para el valor                                          |
| QBit                    | list\[float]            | -                   | NumPy se usa automáticamente para una transposición de bits más rápida cuando está instalado.                                              |

<div id="external-data">
  ## Datos externos
</div>

Las consultas de ClickHouse pueden aceptar datos externos en cualquier formato de entrada admitido. El Client envía los datos como parte de la solicitud, y la consulta puede referirse a ellos como una tabla externa temporal. Consulte la [documentación sobre datos externos de ClickHouse](/es/reference/engines/table-engines/special/external-data). Los métodos de consulta del Client aceptan un objeto `clickhouse_connect.driver.external.ExternalData` mediante el parámetro `external_data`.

| Nombre     | Tipo              | Descripción                                                                                                                                                                                                       |
| ---------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| file\_path | str               | Ruta a un archivo en el sistema local desde la que se leerán los datos externos. Se requiere `file_path` o `data`                                                                                                 |
| file\_name | str               | El nombre del "archivo" de datos externos. Si no se proporciona, se toma de la parte correspondiente al nombre de archivo de `file_path`. El nombre de la tabla externa es el nombre del archivo sin la extensión |
| data       | bytes             | Los datos externos en forma binaria (en lugar de leerse desde un archivo). Se requiere `data` o `file_path`                                                                                                       |
| fmt        | str               | El [formato de entrada](/es/reference/formats) de los datos en ClickHouse. El valor predeterminado es `TSV`                                                                                                       |
| types      | str or seq of str | Una lista de tipos de datos de las columnas en los datos externos. Si es una cadena, los tipos deben separarse con comas. Se requiere `types` o `structure`                                                       |
| structure  | str or seq of str | Una lista de nombres de columna + tipo de dato en los datos (consulte los ejemplos). Se requiere `structure` o `types`                                                                                            |
| mime\_type | str               | Tipo MIME opcional de los datos del archivo. Actualmente, ClickHouse ignora este subencabezado HTTP                                                                                                               |

Este ejemplo realiza un join de un archivo CSV externo con una tabla `directors` almacenada en el server:

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

Se pueden añadir archivos de datos externos adicionales al objeto `ExternalData` inicial mediante el método `add_file`, que acepta los mismos parámetros que el constructor. En HTTP, todos los datos externos se transmiten como parte de una carga de archivos `multi-part/form-data`.

El backend de chDB no admite datos externos.

<div id="time-zones">
  ## Zonas horarias
</div>

Los valores `DateTime` y `DateTime64` de ClickHouse se transmiten como valores numéricos basados en la época Unix. ClickHouse Connect los convierte en objetos `datetime` de Python usando los metadatos de la columna, las sobrescrituras de la consulta y la política de zona horaria del Client.

El Client tiene dos opciones de zona horaria independientes:

* `tz_source` selecciona la zona horaria de respaldo para las columnas sin metadatos explícitos de zona horaria:
  * `"auto"` es la opción predeterminada. Usa la zona horaria del servidor cuando el Client puede resolverla de forma segura a través de los cambios de horario de verano; de lo contrario, usa la zona horaria local.
  * `"server"` siempre usa la zona horaria del servidor.
  * `"local"` siempre usa la zona horaria local del proceso.
* `tz_mode` controla la gestión de la zona horaria:
  * `"naive_utc"` es la opción predeterminada. Los resultados en UTC y equivalentes a UTC se devuelven como objetos `datetime` sin zona horaria, por compatibilidad con versiones anteriores.
  * `"aware"` conserva la `tzinfo` de UTC y devuelve valores UTC con zona horaria.
  * `"schema"` devuelve valores con zona horaria solo cuando el tipo de la columna declara una zona horaria, y valores sin zona horaria para columnas `DateTime`/`DateTime64` sin especificar.

Para las consultas normales `"naive_utc"` y `"aware"`, la zona horaria activa se selecciona en este orden:

1. Una sobrescritura `column_tzs` por columna.
2. Metadatos de zona horaria en el tipo de columna de ClickHouse.
3. La sobrescritura `query_tz` para toda la consulta.
4. La información de zona horaria devuelta con la respuesta HTTP.
5. La zona horaria de respaldo seleccionada por `tz_source`.

`tz_mode="schema"` ignora las zonas horarias de la consulta y de respaldo, pero una sobrescritura explícita de `column_tzs` sigue teniendo prioridad.

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

Los nombres de las zonas horarias se resuelven con el módulo estándar `zoneinfo` de la biblioteca. En Windows, `tzdata` se instala automáticamente. En las imágenes mínimas de Linux sin una base de datos de zonas horarias de IANA, instala `clickhouse-connect[tzdata]`.

Los resultados de Pandas conservan la resolución natural de cada tipo de ClickHouse, como `datetime64[s]` para `DateTime` y `datetime64[ms]` para `DateTime64(3)`. Los métodos de DataFrame basados en Arrow `query_df_arrow` y `query_df_arrow_stream` todavía no implementan `tz_mode="schema"` y mostrarán una advertencia cuando se solicite. `query_arrow` y `query_arrow_stream` devuelven los metadatos de zona horaria de la respuesta Arrow sin cambios.
