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

> Requêtes avancées avec ClickHouse Connect

# Requêtes avancées

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

ClickHouse Connect exécute les requêtes standard dans un `QueryContext`. Le `QueryContext` contient les structures clés utilisées pour construire des requêtes sur la base de données ClickHouse, ainsi que la configuration utilisée pour traiter le résultat en `QueryResult` ou dans une autre structure de données de réponse. Cela inclut la requête elle-même, les paramètres, les settings, les formats de lecture et d’autres propriétés.

Un `QueryContext` peut être obtenu à l’aide de la méthode cliente `create_query_context`. Cette méthode prend les mêmes paramètres que la méthode principale de requête. Ce contexte de requête peut ensuite être transmis aux méthodes `query`, `query_df` ou `query_np` comme argument nommé `context`, à la place de tout ou partie des autres arguments de ces méthodes. Notez que les arguments supplémentaires spécifiés lors de l’appel de la méthode remplaceront toutes les propriétés du QueryContext.

Le cas d’utilisation le plus évident d’un `QueryContext` consiste à envoyer la même requête avec différentes valeurs de paramètres liés. Toutes les valeurs des paramètres peuvent être mises à jour en appelant la méthode `QueryContext.set_parameters` avec un dictionnaire, ou une valeur individuelle peut être mise à jour en appelant `QueryContext.set_parameter` avec la paire `key`, `value` souhaitée.

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

Notez que les `QueryContext` ne sont pas thread-safe, mais vous pouvez en obtenir une copie dans un environnement multithread en appelant la méthode `QueryContext.updated_copy`.

<div id="streaming-queries">
  ## Requêtes en streaming
</div>

Le ClickHouse Connect Client fournit plusieurs méthodes pour récupérer des données sous forme de flux (implémenté sous la forme d’un générateur Python) :

* `query_column_block_stream` -- renvoie les données de la requête par blocs sous forme de séquence de colonnes en utilisant des objets Python natifs
* `query_row_block_stream` -- renvoie les données de la requête sous forme de bloc de lignes en utilisant des objets Python natifs
* `query_rows_stream` -- renvoie les données de la requête sous forme de séquence de lignes en utilisant des objets Python natifs
* `query_np_stream` -- renvoie chaque bloc ClickHouse de données de requête sous forme de tableau NumPy
* `query_df_stream` -- renvoie chaque bloc ClickHouse de données de requête sous forme de Pandas DataFrame
* `query_arrow_stream` -- renvoie les données de la requête sous forme d’objets PyArrow `RecordBatch`
* `query_df_arrow_stream` -- renvoie chaque batch Arrow sous forme de Pandas DataFrame ou de Polars DataFrame, sélectionné par `dataframe_library`

Chaque méthode renvoie un `StreamContext` qui doit être ouvert avec une instruction `with`. Les méthodes de streaming du client async sont attendues et ouvertes avec `async with`.

<div id="data-blocks">
  ### Blocs de données
</div>

ClickHouse Connect traite toutes les données de la méthode principale `query` comme un flux de blocs reçus du serveur ClickHouse. Ces blocs sont transmis depuis et vers ClickHouse dans le format personnalisé « Native ». Un « bloc » est simplement une séquence de colonnes de données binaires, où chaque colonne contient le même nombre de valeurs du type de données spécifié. (En tant que base de données colonnaire, ClickHouse stocke ces données sous une forme similaire.) La taille d’un bloc renvoyé par une requête est régie par deux paramètres utilisateur qui peuvent être définis à plusieurs niveaux (profil utilisateur, utilisateur, session ou requête). Il s’agit de :

* [max\_block\_size](/fr/reference/settings/session-settings#max_block_size) -- Taille maximale du bloc en lignes.
* [preferred\_block\_size\_bytes](/fr/reference/settings/session-settings#preferred_block_size_bytes) -- Taille de bloc préférée en octets.

Indépendamment de `preferred_block_size_bytes`, un bloc ne dépassera pas `max_block_size` lignes. La taille réelle peut être plus petite et ne doit pas être considérée comme stable.

Lors de l’utilisation de l’une des méthodes `query_*_stream` du Client, les résultats sont renvoyés bloc par bloc. ClickHouse Connect ne charge qu’un seul bloc à la fois. Cela permet de traiter de grandes quantités de données sans devoir charger en mémoire l’intégralité d’un ensemble de résultats volumineux. Notez que l’application doit être prête à traiter un nombre quelconque de blocs et que la taille exacte de chaque bloc ne peut pas être contrôlée.

<div id="http-data-buffer-for-slow-processing">
  ### Buffer de données HTTP pour un traitement lent
</div>

Si une application consomme les blocs bien plus lentement que le serveur ne les produit, la connexion HTTP peut se fermer avant la fin du traitement. Augmentez le paramètre global `http_buffer_size` si l’application dispose de suffisamment de mémoire pour mettre en mémoire tampon davantage de données de réponse. La valeur par défaut est de 10 MiB. Les octets de réponse lz4 et zstd restent compressés dans ce buffer, ce qui en augmente la capacité effective.

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

Chacune des méthodes `query_*_stream` (comme `query_row_block_stream`) renvoie un objet ClickHouse `StreamContext`, qui combine un contexte Python et un générateur. Voici l’utilisation de base :

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

Notez qu’essayer d’utiliser un StreamContext sans bloc `with` provoquera une erreur. L’utilisation d’un contexte Python garantit que le flux (dans ce cas, une réponse HTTP en streaming) sera correctement fermé, même si toutes les données ne sont pas consommées et/ou si une exception est levée pendant le traitement. De plus, les `StreamContext` ne peuvent être utilisés qu’une seule fois pour consommer le flux. Essayer d’utiliser un `StreamContext` après avoir quitté son contexte produira une `StreamClosedError`.

Si la connexion échoue pendant la lecture d’un résultat, une `StreamFailureError` est levée au lieu de renvoyer silencieusement un résultat tronqué. Son message respecte le paramètre `show_clickhouse_errors` du client.

Vous pouvez utiliser la propriété `source` du `StreamContext` pour accéder à l’objet résultat parent, qui inclut les noms de colonnes et les types. Pour la plupart des flux, il s’agit d’un `QueryResult` ; les méthodes `query_np_stream` et `query_df_stream` exposent à la place un `NumpyResult`.

<div id="stream-types">
  ### Types de flux
</div>

La méthode `query_column_block_stream` renvoie le bloc sous la forme d’une séquence de données de colonnes stockées dans des data types Python natifs. En reprenant les queries `taxi_trips` ci-dessus, les données renvoyées seront une liste dans laquelle chaque élément est lui-même une liste (ou un tuple) contenant toutes les données de la colonne correspondante. Ainsi, `block[0]` serait un tuple ne contenant que des chaînes de caractères. Les formats orientés colonnes sont surtout utilisés pour effectuer des opérations d’agrégation sur toutes les valeurs d’une colonne, par exemple pour additionner le montant total des courses.

La méthode `query_row_block_stream` renvoie le bloc sous la forme d’une séquence de lignes, comme dans une base de données relationnelle classique. Pour les trajets de taxi, les données renvoyées seront une liste dans laquelle chaque élément est lui-même une liste représentant une ligne de données. Ainsi, `block[0]` contiendrait tous les champs (dans l’ordre) du premier trajet de taxi, `block[1]` contiendrait tous les champs du deuxième trajet de taxi, et ainsi de suite. Les résultats orientés lignes sont généralement utilisés pour l’affichage ou les processus de transformation.

La méthode `query_rows_stream` passe automatiquement au bloc suivant et renvoie une ligne à la fois. C’est l’équivalent ligne par ligne de `query_row_block_stream`.

La méthode `query_np_stream` renvoie chaque bloc sous la forme d’un Array NumPy. Lorsque toutes les colonnes de résultat partagent le même Dtype NumPy, le Array est bidimensionnel avec la shape `(rows, columns)`. Les résultats mixtes sont renvoyés sous la forme d’un Array structuré unidimensionnel ou utilisent le dtype object.

La méthode `query_df_stream` renvoie chaque bloc ClickHouse sous la forme d’un Pandas DataFrame à deux dimensions. Voici un Example montrant que l’objet `StreamContext` peut être utilisé comme contexte de manière différée (mais une seule fois).

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

La méthode `query_df_arrow_stream` convertit les batches Arrow en DataFrames Pandas ou Polars. Sélectionnez la bibliothèque avec `dataframe_library`, dont la valeur par défaut est `"pandas"`.

Enfin, `query_arrow_stream` encapsule une réponse `ArrowStream` de ClickHouse dans un `StreamContext`. Chaque itération renvoie un `RecordBatch` PyArrow.

<div id="streaming-examples">
  ### Exemples en streaming
</div>

<div id="stream-rows">
  #### Flux de lignes
</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">
  #### flux de blocs de lignes
</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">
  #### Flux de DataFrames 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">
  #### Flux de lots 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">
  #### Flux de lignes asynchrone
</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">
  ## Requêtes NumPy, Pandas et Arrow
</div>

ClickHouse Connect propose des méthodes de requête spécialisées pour manipuler les structures de données NumPy, Pandas et Arrow. Ces méthodes vous permettent de récupérer le résultat de la requête directement dans ces formats de données courants, sans conversion manuelle.

<div id="numpy-queries">
  ### Requêtes NumPy
</div>

La méthode `query_np` renvoie le résultat de la requête sous la forme d'un tableau NumPy plutôt que d'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">
  ### Requêtes Pandas
</div>

La méthode `query_df` renvoie le résultat de la requête sous forme de Pandas DataFrame plutôt que de `QueryResult` 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">
  ### Requêtes PyArrow
</div>

La méthode `query_arrow` renvoie une PyArrow Table en utilisant directement le format `Arrow` de ClickHouse. Elle accepte `query`, `parameters`, `settings`, `external_data` et `transport_settings`. L’option `use_strings` contrôle si les colonnes `String` de ClickHouse sont renvoyées sous forme de chaînes Arrow ou de valeurs binaires.

```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 basés sur Arrow
</div>

ClickHouse Connect prend en charge la création efficace de DataFrames à partir de résultats Arrow via `query_df_arrow` et `query_df_arrow_stream`. Ces méthodes évitent la conversion via des objets ligne Python et réutilisent les tampons Arrow lorsque la bibliothèque cible le permet :

* `query_df_arrow` : exécute la requête en utilisant le format de sortie ClickHouse `Arrow` et renvoie un DataFrame.
  * `dataframe_library="pandas"` renvoie un DataFrame Pandas 2.0 ou version ultérieure en utilisant `pd.ArrowDtype`.
  * `dataframe_library="polars"` renvoie un DataFrame Polars créé via `pl.from_arrow`.
* `query_df_arrow_stream` : diffuse des batches Arrow sous forme de DataFrames Pandas ou Polars.

<div id="query-to-arrow-backed-dataframe">
  #### Requête vers un DataFrame basé sur 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">
  #### Remarques et mises en garde
</div>

* ClickHouse contrôle le schéma Arrow. Les types sans représentation Arrow directe peuvent être renvoyés à l’aide d’un type physique compatible, y compris des champs binaires. Inspectez `table.schema` ou les dtypes du DataFrame avant d’appliquer des conversions spécifiques à l’application.
* Les résultats Pandas basés sur Arrow nécessitent Pandas 2.0 ou version ultérieure.
* `use_strings` détermine si les colonnes ClickHouse `String` utilisent des champs de chaîne Arrow ou des champs binaires lorsque le serveur prend en charge `output_format_arrow_string_as_string`.
* `tz_mode="schema"` n’est pas encore pris en charge par les méthodes de requête basées sur Arrow. Elles émettent un avertissement et conservent les métadonnées de fuseau horaire fournies par la réponse Arrow.

<div id="read-formats">
  ## Formats de lecture
</div>

Les formats de lecture contrôlent les valeurs renvoyées par `query`, `query_np` et `query_df`. Ils ne s'appliquent pas aux méthodes raw ou Arrow, car ces méthodes utilisent directement un format de sortie du serveur. Par exemple, définir le format de lecture de UUID sur `"string"` renvoie des chaînes UUID au lieu d'objets `uuid.UUID`.

L'argument "data type" de toute fonction de mise en forme peut inclure des caractères génériques. Le format est une chaîne unique en minuscules. Les wrappers de conteneur tels que `Array`, `Nullable` et `LowCardinality` conservent le format sélectionné pour leur type d'élément.

Les formats de lecture peuvent être définis à plusieurs niveaux :

* Globalement, à l'aide des méthodes définies dans le paquet `clickhouse_connect.datatypes.format`. Cela contrôle le format du type de données configuré pour toutes les requêtes.

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

* Pour l’ensemble d’une requête, en utilisant l’argument de dictionnaire facultatif `query_formats`. Dans ce cas, toute colonne (ou sous-colonne) des types de données spécifiés utilisera le format configuré.

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

* Pour une colonne de résultat donnée, utilisez le dictionnaire facultatif `column_formats`. Chaque clé correspond à un nom de colonne renvoyé. Sa valeur est soit une chaîne de format, soit une correspondance imbriquée associant des noms de type ClickHouse à des formats, ce qui est utile pour les Tuples, les Maps et d'autres types de conteneurs.

```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">
  ### Options de format de lecture (types Python)
</div>

| ClickHouse Type         | Type Python natif       | Formats de lecture | Commentaires                                                                                                                                         |
| ----------------------- | ----------------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| Int\[8-64], UInt\[8-32] | int                     | string             |                                                                                                                                                      |
| UInt64                  | int                     | signed             | Superset ne gère pas actuellement les grandes valeurs UInt64 non signées                                                                             |
| \[U]Int\[128,256]       | int                     | string             | Les valeurs int de Pandas et NumPy sont limitées à 64 bits au maximum, elles peuvent donc être renvoyées sous forme de chaînes                       |
| BFloat16                | float                   | -                  | Tous les float Python utilisent en interne 64 bits                                                                                                   |
| Float32                 | float                   | string             | Tous les float Python utilisent en interne 64 bits                                                                                                   |
| Float64                 | float                   | string             |                                                                                                                                                      |
| Decimal                 | decimal.Decimal         | -                  |                                                                                                                                                      |
| String                  | str                     | bytes              | Les colonne de type String ClickHouse n'ont pas d'encodage intrinsèque, elles servent donc aussi à stocker des données binaires de longueur variable |
| FixedString             | bytes                   | string             | Les FixedString sont des tableaux d'octets de taille fixe, mais sont parfois traités comme des chaînes Python                                        |
| Enum\[8,16]             | str                     | int                | Le Native format renvoie les labels ; `int` renvoie l'entier sous-jacent.                                                                            |
| Date                    | datetime.date           | int                | Le format entier renvoie le nombre de jours depuis le 1970-01-01.                                                                                    |
| Date32                  | datetime.date           | int                | Le format entier renvoie un décalage en jours signé plus large.                                                                                      |
| DateTime                | datetime.datetime       | int                | Le format entier renvoie les secondes depuis l'epoch.                                                                                                |
| DateTime64              | datetime.datetime       | int                | Le format entier renvoie les ticks à la précision de la colonne. Python `datetime` est limité aux microsecondes.                                     |
| Time                    | datetime.timedelta      | int, string, time  | Le format entier renvoie les secondes. Le format `time` est limité aux valeurs compatibles avec `datetime.time`.                                     |
| Time64                  | datetime.timedelta      | int, string, time  | Le format entier renvoie les ticks à la précision de la colonne. Python `timedelta` est limité aux microsecondes.                                    |
| IPv4                    | `ipaddress.IPv4Address` | string, int        | Les adresses IP peuvent être lues sous forme de chaînes ou d'entiers.                                                                                |
| IPv6                    | `ipaddress.IPv6Address` | string             | Les adresses IP peuvent être lues sous forme de chaînes et, si elles sont correctement formatées, insérées comme adresses IP                         |
| Tuple                   | dict or tuple           | tuple, dict, json  | Les tuples nommés renvoient des dictionnaires par défaut ; les tuples non nommés renvoient des tuples.                                               |
| Map                     | dict                    | -                  |                                                                                                                                                      |
| Nested                  | Sequence\[dict]         | -                  |                                                                                                                                                      |
| UUID                    | uuid.UUID               | string             | Les UUIDs peuvent être lus comme des chaînes formatées conformément à la RFC 4122<br />                                                              |
| JSON                    | dict                    | string             | Un dictionnaire Python est renvoyé par défaut. Le format `string` renvoie une chaîne JSON                                                            |
| Variant                 | object                  | typed              | `typed` renvoie `TypedVariant(value, type_name)` afin de préserver le type membre d'origine.                                                         |
| Dynamic                 | object                  | -                  | Renvoie le type Python correspondant au type de données ClickHouse stocké pour la valeur                                                             |
| QBit                    | list\[float]            | -                  | NumPy est utilisé automatiquement pour une transposition des bits plus rapide lorsqu'il est installé.                                                |

<div id="external-data">
  ## Données externes
</div>

Les requêtes ClickHouse peuvent accepter des données externes dans n’importe quel format d’entrée pris en charge. Le client envoie les données avec la requête, et celle-ci peut y faire référence comme à une table externe temporaire. Consultez la [documentation ClickHouse sur les données externes](/fr/reference/engines/table-engines/special/external-data). Les méthodes de requête du client acceptent un objet `clickhouse_connect.driver.external.ExternalData` via le paramètre `external_data`.

| Nom        | Type              | Description                                                                                                                                                                                  |
| ---------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| file\_path | str               | Chemin d’un fichier sur le système local à partir duquel lire les données externes. `file_path` ou `data` est requis                                                                         |
| file\_name | str               | Nom du « fichier » de données externes. S’il n’est pas fourni, il est déduit de la partie nom de fichier de `file_path`. Le nom de la table externe est le nom du fichier sans son extension |
| data       | bytes             | Les données externes sous forme binaire (au lieu d’être lues depuis un fichier). `data` ou `file_path` est requis                                                                            |
| fmt        | str               | Le [format d’entrée](/fr/reference/formats) ClickHouse des données. La valeur par défaut est `TSV`                                                                                           |
| types      | str or seq of str | Une liste des types de données des colonnes dans les données externes. S’il s’agit d’une chaîne, les types doivent être séparés par des virgules. `types` ou `structure` est requis          |
| structure  | str or seq of str | Une liste de paires nom de colonne + type de données dans les données (voir les exemples). `structure` ou `types` est requis                                                                 |
| mime\_type | str               | Type MIME facultatif des données du fichier. Actuellement, ClickHouse ignore ce sous-en-tête HTTP                                                                                            |

Cet exemple effectue une jointure entre un fichier CSV externe et une table `directors` stockée sur le serveur :

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

Des fichiers de données externes supplémentaires peuvent être ajoutés à l’objet `ExternalData` initial à l’aide de la méthode `add_file`, qui prend les mêmes paramètres que le constructeur. En HTTP, toutes les données externes sont transmises dans le cadre d’un téléversement de fichiers `multi-part/form-data`.

Le backend chDB ne prend pas en charge les données externes.

<div id="time-zones">
  ## Fuseaux horaires
</div>

Les valeurs ClickHouse `DateTime` et `DateTime64` sont transmises sous forme de valeurs numériques basées sur l’epoch. ClickHouse Connect les convertit en objets Python `datetime` à l’aide des métadonnées des colonnes, des redéfinitions de requête et de la politique de fuseau horaire du client.

Le client dispose de deux options de fuseau horaire indépendantes :

* `tz_source` sélectionne le fuseau horaire de repli pour les colonnes sans métadonnées de fuseau horaire explicites :
  * `"auto"` est la valeur par défaut. Il utilise le fuseau horaire du serveur lorsque le client peut le déterminer de manière fiable malgré les changements d’heure, sinon il utilise le fuseau horaire local.
  * `"server"` utilise toujours le fuseau horaire du serveur.
  * `"local"` utilise toujours le fuseau horaire du processus local.
* `tz_mode` contrôle le mode de gestion du fuseau horaire :
  * `"naive_utc"` est la valeur par défaut. Les résultats UTC et équivalents à UTC sont renvoyés comme des objets `datetime` naïfs pour assurer la compatibilité descendante.
  * `"aware"` conserve le `tzinfo` UTC et renvoie des valeurs UTC avec fuseau horaire.
  * `"schema"` renvoie des valeurs avec fuseau horaire uniquement lorsque le type de colonne déclare un fuseau horaire, et des valeurs naïves pour les colonnes `DateTime`/`DateTime64` sans fuseau horaire.

Pour les requêtes ordinaires `"naive_utc"` et `"aware"`, le fuseau horaire actif est sélectionné dans cet ordre :

1. Une redéfinition `column_tzs` par colonne.
2. Les métadonnées de fuseau horaire du type de colonne ClickHouse.
3. La redéfinition `query_tz` pour l’ensemble de la requête.
4. Les informations de fuseau horaire renvoyées avec la réponse HTTP.
5. Le fuseau de repli sélectionné par `tz_source`.

`tz_mode="schema"` ignore les fuseaux horaires de requête et de repli, mais une redéfinition `column_tzs` explicite reste prioritaire.

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

Les noms de fuseaux horaires sont résolus à l’aide du module `zoneinfo` de la bibliothèque standard. Les installations sous Windows reçoivent automatiquement `tzdata`. Sur les images Linux minimales dépourvues de base de données de fuseaux horaires IANA, installez `clickhouse-connect[tzdata]`.

Les résultats Pandas conservent la résolution naturelle de chaque type ClickHouse, par exemple `datetime64[s]` pour `DateTime` et `datetime64[ms]` pour `DateTime64(3)`. Les méthodes DataFrame basées sur Arrow `query_df_arrow` et `query_df_arrow_stream` ne prennent pas encore en charge `tz_mode="schema"` et émettent un avertissement lorsqu’il est demandé. `query_arrow` et `query_arrow_stream` renvoient les métadonnées de fuseau horaire de la réponse Arrow sans les modifier.
