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

> Documentation sur CREATE VIEW

# CREATE VIEW

export const CloudNotSupportedBadge = () => {
  return <div className="cloudNotSupportedBadge">
            <div className="cloudNotSupportedIcon">
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path strokeWidth="1.5" d="M6.33366 12.6666L12.3739 12.6667C13.6593 12.6667 14.7073 11.6187 14.7073 10.3334C14.7073 9.04804 13.6593 8.00003 12.3739 8.00003C12.3739 8.00003 12.3337 7.66659 12.0003 7.33325M10.667 5.33322C8.00033 2.33325 4.45395 4.78537 4.14195 6.68203C2.55728 6.7627 1.29395 8.06203 1.29395 9.6667C1.29395 11.3234 2.66699 12.6666 4.00033 12.6666" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.5" d="M2.66699 14L12.0003 4.66663" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
            </svg>

        </div>
            Non pris en charge par ClickHouse Cloud
        </div>;
};

export const DeprecatedBadge = () => {
  return <div className="deprecatedBadge">
            <div className="deprecatedIcon">
            <svg width="14" height="10" viewBox="0 0 14 10" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path d="M13 0H1C0.734784 0 0.48043 0.105357 0.292893 0.292893C0.105357 0.48043 0 0.734784 0 1V2.5C0 2.76522 0.105357 3.01957 0.292893 3.20711C0.48043 3.39464 0.734784 3.5 1 3.5V9C1 9.26522 1.10536 9.51957 1.29289 9.70711C1.48043 9.89464 1.73478 10 2 10H12C12.2652 10 12.5196 9.89464 12.7071 9.70711C12.8946 9.51957 13 9.26522 13 9V3.5C13.2652 3.5 13.5196 3.39464 13.7071 3.20711C13.8946 3.01957 14 2.76522 14 2.5V1C14 0.734784 13.8946 0.48043 13.7071 0.292893C13.5196 0.105357 13.2652 0 13 0ZM12 9H2V3.5H12V9ZM13 2.5H1V1H13V2.5ZM5 5.5C5 5.36739 5.05268 5.24021 5.14645 5.14645C5.24021 5.05268 5.36739 5 5.5 5H8.5C8.63261 5 8.75979 5.05268 8.85355 5.14645C8.94732 5.24021 9 5.36739 9 5.5C9 5.63261 8.94732 5.75979 8.85355 5.85355C8.75979 5.94732 8.63261 6 8.5 6H5.5C5.36739 6 5.24021 5.94732 5.14645 5.85355C5.05268 5.75979 5 5.63261 5 5.5Z" fill="currentColor" />
            </svg>
        </div>
            Fonctionnalité dépréciée
        </div>;
};

export const ExperimentalBadge = () => {
  return <div className="experimentalBadge">
            <div className="experimentalIcon">
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path strokeWidth="1.25" d="M5.5 2H10.5" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.25" d="M9.50015 2V6.19625L13.4283 12.7425C13.4738 12.8183 13.4985 12.9049 13.4996 12.9934C13.5008 13.0818 13.4785 13.169 13.435 13.246C13.3914 13.323 13.3283 13.3871 13.2519 13.4317C13.1755 13.4764 13.0886 13.4999 13.0002 13.5H3.00015C2.91164 13.5 2.8247 13.4766 2.74822 13.432C2.67174 13.3874 2.60847 13.3233 2.56487 13.2463C2.52126 13.1693 2.49889 13.082 2.50004 12.9935C2.50119 12.905 2.52582 12.8184 2.5714 12.7425L6.50015 6.19625V2" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.25" d="M4.47656 9.56754C5.30344 9.41254 6.47656 9.47942 7.99969 10.25C10.0153 11.2707 11.4216 11.0569 12.2184 10.7282" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
        </div>
            Fonctionnalité expérimentale. <u><a href="/docs/beta-and-experimental-features#experimental-features">En savoir plus.</a></u>
        </div>;
};

Crée une nouvelle vue. Les vues peuvent être [normales](#normal-view), [matérialisées](#materialized-view), [matérialisées actualisables](#refreshable-materialized-view) et [de fenêtre](/fr/reference/statements/create/view#window-view).

<div id="normal-view">
  ## Vue normale
</div>

Syntaxe :

```sql theme={null}
CREATE [OR REPLACE] VIEW [IF NOT EXISTS] [db.]table_name [(alias1 [, alias2 ...])] [ON CLUSTER cluster_name]
[DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | INVOKER | NONE }]
AS SELECT ...
[COMMENT 'comment']
```

Les vues normales ne stockent aucune donnée. Elles se contentent de lire une autre table à chaque accès. Autrement dit, une vue normale n’est rien d’autre qu’une requête enregistrée. Lorsqu’on lit depuis une vue, cette requête enregistrée est utilisée comme sous-requête dans la clause [FROM](/fr/reference/statements/select/from).

À titre d’exemple, supposons que vous ayez créé une vue :

```sql theme={null}
CREATE VIEW view AS SELECT ...
```

et rédigé une requête :

```sql theme={null}
SELECT a, b, c FROM view
```

Cette requête est strictement équivalente à l’utilisation de la sous-requête :

```sql theme={null}
SELECT a, b, c FROM (SELECT ...)
```

<div id="parameterized-view">
  ## Vue paramétrée
</div>

Les vues paramétrées sont similaires aux vues normales, mais elles peuvent être créées avec des paramètres qui ne sont pas évalués immédiatement. Ces vues peuvent être utilisées avec des fonctions de table, en utilisant le nom de la vue comme nom de fonction et les valeurs des paramètres comme arguments.

```sql theme={null}
CREATE VIEW view AS SELECT * FROM TABLE WHERE Column1={column1:datatype1} and Column2={column2:datatype2} ...
```

Ce qui précède crée une vue sur la table, qui peut être utilisée comme fonction de table en remplaçant les paramètres, comme indiqué ci-dessous.

```sql theme={null}
SELECT * FROM view(column1=value1, column2=value2 ...)
```

<div id="materialized-view">
  ## Vue matérialisée
</div>

```sql theme={null}
CREATE MATERIALIZED VIEW [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster_name] [TO[db.]name [(columns)]] [ENGINE = engine] [POPULATE]
[REFRESH ...]
[DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | NONE }]
AS SELECT ...
[COMMENT 'comment']
```

```sql theme={null}
CREATE OR REPLACE MATERIALIZED VIEW [db.]table_name [ON CLUSTER cluster_name] [TO[db.]name [(columns)]] [ENGINE = engine] [POPULATE]
[REFRESH ...]
[DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | NONE }]
AS SELECT ...
[COMMENT 'comment']
```

`OR REPLACE` et `IF NOT EXISTS` sont mutuellement exclusifs : les combiner provoque une erreur de syntaxe.

<div id="create-or-replace-materialized-view">
  ### CREATE OR REPLACE MATERIALIZED VIEW
</div>

`CREATE OR REPLACE MATERIALIZED VIEW` remplace de manière atomique une vue matérialisée existante ainsi que sa table de stockage interne, s’il y en a une. Cette opération nécessite un moteur de base de données `Atomic` ou `Replicated`.

```sql theme={null}
CREATE OR REPLACE MATERIALIZED VIEW [db.]name [ON CLUSTER cluster]
[TO [db.]target_table]
[ENGINE = engine]
[POPULATE]
[REFRESH ...]
AS SELECT ...
```

Comportements clés :

* **Sans clause `TO`** : l’ancienne table interne est supprimée et une nouvelle est créée. Les données existantes de la table interne sont perdues, sauf si `POPULATE` est spécifié.
* **Avec clause `TO`** : seule la définition de la vue est remplacée ; la table cible et ses données ne sont pas affectées.
* Compatible avec `REFRESH`, `ON CLUSTER` et toutes les options de moteur. `POPULATE` est pris en charge uniquement pour les bases de données `Atomic` — il est rejeté pour les bases de données `Replicated` (voir la note `POPULATE` ci-dessous).
* Nécessite les privilèges `CREATE VIEW` et `DROP VIEW`.

<Note>
  `CREATE OR REPLACE MATERIALIZED VIEW` n’est pris en charge qu’avec les moteurs de base de données `Atomic` ou `Replicated`. Il n’est pas pris en charge avec le moteur de base de données `Ordinary`.
</Note>

**Exemples :**

```sql theme={null}
-- Create a materialized view with an inner table
CREATE OR REPLACE MATERIALIZED VIEW mv
    ENGINE = MergeTree ORDER BY x
    AS SELECT x, sum(y) AS total FROM src GROUP BY x;

-- Replace with a new definition (old inner table data is lost)
CREATE OR REPLACE MATERIALIZED VIEW mv
    ENGINE = MergeTree ORDER BY x
    AS SELECT x, count() AS cnt FROM src GROUP BY x;

-- Replace with POPULATE to backfill from existing source data
CREATE OR REPLACE MATERIALIZED VIEW mv
    ENGINE = MergeTree ORDER BY x
    POPULATE
    AS SELECT x FROM src;

-- Replace an inner-table MV with a TO-table MV (target data is preserved)
CREATE OR REPLACE MATERIALIZED VIEW mv TO target
    AS SELECT x FROM src;
```

<Tip>
  Voici un guide étape par étape sur l’utilisation des [vues matérialisées](/fr/concepts/features/materialized-views/cascading-materialized-views).
</Tip>

Les vues matérialisées stockent les données transformées par la requête [SELECT](/fr/reference/statements/select/index) correspondante.

Lors de la création d’une vue matérialisée sans `TO [db].[table]`, vous devez spécifier `ENGINE` — le moteur de table utilisé pour stocker les données.

Lors de la création d’une vue matérialisée avec `TO [db].[table]`, vous ne pouvez pas non plus utiliser `POPULATE`.

Une vue matérialisée fonctionne comme suit : lors de l’insertion de données dans la table spécifiée dans `SELECT`, une partie des données insérées est transformée par cette requête `SELECT`, puis le résultat est inséré dans la vue.

<Note>
  Les vues matérialisées dans ClickHouse utilisent les **noms de colonnes** plutôt que l’ordre des colonnes lors de l’insertion dans la table de destination. Si certains noms de colonnes ne figurent pas dans le résultat de la requête `SELECT`, ClickHouse utilise une valeur par défaut, même si la colonne n’est pas [Nullable](/fr/reference/data-types/nullable). Une bonne pratique consiste à ajouter des alias pour chaque colonne lors de l’utilisation de vues matérialisées.

  Les vues matérialisées dans ClickHouse sont davantage implémentées comme des déclencheurs à l’insertion. S’il y a une agrégation dans la requête de la vue, elle ne s’applique qu’au lot de données nouvellement insérées. Toute modification des données existantes de la table source (comme update, delete, drop partition, etc.) ne modifie pas la vue matérialisée.

  Les vues matérialisées dans ClickHouse n’ont pas de comportement déterministe en cas d’erreur. Cela signifie que les blocs déjà écrits sont conservés dans la table de destination, mais que tous les blocs suivant l’erreur ne le sont pas.

  Par défaut, si l’envoi vers l’une des vues génère une exception, la requête `INSERT` échoue. Rien ne garantit qu’à ce stade le bloc ait déjà atteint la table source — cela dépend du moment où il se trouve dans le pipeline d’insertion, et non de l’erreur de la vue. Réessayez l’`INSERT` ayant échoué avec la déduplication d’insertion (`insert_deduplicate`, `deduplicate_blocks_in_dependent_materialized_views`) pour obtenir une livraison exactly-once vers la table source et toutes les vues dépendantes.

  Définir `materialized_views_ignore_errors=true` sur la requête `INSERT` modifie uniquement le signalement des erreurs : chaque erreur de vue est consignée comme un avertissement et la requête `INSERT` réussit. La livraison vers la destination de la vue en échec est partielle — les blocs traités avant l’exception sont conservés, et le bloc en échec ainsi que tous les blocs suivants sont ignorés pour cette vue. Les vues en aval de cette destination ne voient que les blocs effectivement arrivés, leur livraison est donc elle aussi partielle. Les vues sœurs (et leurs chaînes en aval) qui n’ont pas généré d’exception sont, elles, écrites intégralement, et la table source est alimentée comme d’habitude. Comme l’`INSERT` est signalé comme réussi, le client ne reçoit aucun signal d’échec et aucun nouvel essai automatique n’est déclenché ; utilisez ce paramètre uniquement lorsque les écritures dans la table source ne doivent pas être bloquées par des problèmes du côté des vues (par exemple, les tables `system.*_log`).

  `materialized_views_ignore_errors` vaut `true` par défaut pour les tables `system.*_log`.
</Note>

Si vous spécifiez `POPULATE`, les données existantes de la table sont insérées dans la vue lors de sa création, comme avec un `CREATE TABLE ... AS SELECT ...`. Sinon, la requête ne contient que les données insérées dans la table après la création de la vue. Nous **ne recommandons pas** d’utiliser `POPULATE`, car les données insérées dans la table pendant la création de la vue n’y seront pas insérées.

<Note>
  Étant donné que `POPULATE` fonctionne comme `CREATE TABLE ... AS SELECT ...`, il présente des limitations :

  * Il n’est pas pris en charge avec une base de données Replicated
  * Il n’est pas pris en charge dans ClickHouse Cloud

  À la place, vous pouvez utiliser un `INSERT ... SELECT` distinct.
</Note>

Une requête `SELECT` peut contenir `DISTINCT`, `GROUP BY`, `ORDER BY`, `LIMIT`. Notez que les transformations correspondantes sont effectuées indépendamment sur chaque bloc de données insérées. Par exemple, si `GROUP BY` est défini, les données sont agrégées pendant l’insertion, mais uniquement à l’intérieur d’un seul paquet de données insérées. Les données ne seront pas agrégées davantage. L’exception est l’utilisation d’un `ENGINE` qui effectue lui-même l’agrégation des données, comme `SummingMergeTree`.

Si la vue matérialisée utilise la construction `TO [db.]name`, vous pouvez `DETACH` la vue, exécuter `ALTER` sur la table cible, puis `ATTACH` la vue précédemment détachée (`DETACH`).

Notez que la vue matérialisée est influencée par le paramètre [optimize\_on\_insert](/fr/reference/settings/session-settings#optimize_on_insert). Les données sont fusionnées avant l’insertion dans une vue.

Les vues se présentent comme des tables normales. Par exemple, elles figurent dans le résultat de la requête `SHOW TABLES`.

Pour supprimer une vue, utilisez [DROP VIEW](/fr/reference/statements/drop#drop-view). Bien que `DROP TABLE` fonctionne également pour les VIEWs.

<div id="sql_security">
  ## Sécurité SQL
</div>

`DEFINER` et `SQL SECURITY` permettent de spécifier quel utilisateur ClickHouse utiliser lors de l’exécution de la requête sous-jacente de la vue.
`SQL SECURITY` a trois valeurs possibles : `DEFINER`, `INVOKER` ou `NONE`. Vous pouvez spécifier n’importe quel utilisateur existant ou `CURRENT_USER` dans la clause `DEFINER`.

Le tableau suivant indique quels droits sont requis pour quel utilisateur afin d’interroger la vue.
Notez que, quelle que soit l’option de sécurité SQL, il est dans tous les cas nécessaire d’avoir `GRANT SELECT ON <view>` pour pouvoir la lire.

| Option de sécurité SQL | Vue                                                                          | Vue matérialisée                                                                                                         |
| ---------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `DEFINER alice`        | `alice` doit disposer du droit `SELECT` sur la table source de la vue.       | `alice` doit disposer du droit `SELECT` sur la table source de la vue et du droit `INSERT` sur la table cible de la vue. |
| `INVOKER`              | L’utilisateur doit disposer du droit `SELECT` sur la table source de la vue. | `SQL SECURITY INVOKER` ne peut pas être spécifié pour les vues matérialisées.                                            |
| `NONE`                 | -                                                                            | -                                                                                                                        |

<Note>
  `SQL SECURITY NONE` est une option obsolète. Tout utilisateur disposant des droits pour créer des vues avec `SQL SECURITY NONE` pourra exécuter n’importe quelle requête arbitraire.
  Il est donc nécessaire d’avoir `GRANT ALLOW SQL SECURITY NONE TO <user>` pour créer une vue avec cette option.
</Note>

Si `DEFINER`/`SQL SECURITY` ne sont pas spécifiés, les valeurs par défaut sont utilisées :

* `SQL SECURITY` : `INVOKER` pour les vues normales et `DEFINER` pour les vues matérialisées ([configurable dans les paramètres](/fr/reference/settings/session-settings#default_normal_view_sql_security))
* `DEFINER` : `CURRENT_USER` ([configurable dans les paramètres](/fr/reference/settings/session-settings#default_view_definer))

Si une vue est Attach sans que `DEFINER`/`SQL SECURITY` soient spécifiés, la valeur par défaut est `SQL SECURITY NONE` pour la vue matérialisée et `SQL SECURITY INVOKER` pour la vue normale.

Pour modifier la sécurité SQL d’une vue existante, utilisez

```sql theme={null}
ALTER TABLE MODIFY SQL SECURITY { DEFINER | INVOKER | NONE } [DEFINER = { user | CURRENT_USER }]
```

<div id="examples">
  ### Exemples
</div>

```sql theme={null}
CREATE VIEW test_view
DEFINER = alice SQL SECURITY DEFINER
AS SELECT ...
```

```sql theme={null}
CREATE VIEW test_view
SQL SECURITY INVOKER
AS SELECT ...
```

<div id="live-view">
  ## Live View
</div>

Cette fonctionnalité est obsolète et sera supprimée à l’avenir.

Pour vous faciliter la tâche, l’ancienne documentation est disponible [ici](https://pastila.nl/?00f32652/fdf07272a7b54bda7e13b919264e449f.md)

<div id="refreshable-materialized-view">
  ## Vue matérialisée actualisable
</div>

```sql theme={null}
CREATE MATERIALIZED VIEW [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
REFRESH [EVERY|AFTER interval [OFFSET interval]]
[RANDOMIZE FOR interval]
[DEPENDS ON [db.]name [, [db.]name [, ...]]]
[SETTINGS name = value [, name = value [, ...]]]
[APPEND]
[TO[db.]name] [(columns)] [ENGINE = engine]
[EMPTY]
[DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | NONE }]
AS SELECT ...
[COMMENT 'comment']
```

où `interval` correspond à une suite d'intervalles simples :

```sql theme={null}
number SECOND|MINUTE|HOUR|DAY|WEEK|MONTH|YEAR
```

La clause `REFRESH` doit spécifier au moins l’un des éléments suivants : `EVERY`, `AFTER` ou `DEPENDS ON`. Un `REFRESH` seul (sans aucun d’eux) est rejeté. `REFRESH DEPENDS ON ...` sans `EVERY`/`AFTER` est une forme abrégée de `REFRESH AFTER 0 SECOND DEPENDS ON ...` ; voir [Dépendances de rafraîchissement](#refresh-dependencies) ci-dessous.

Exécute périodiquement la requête correspondante et stocke son résultat dans une table.

* Si `APPEND` est spécifié, chaque rafraîchissement insère des lignes dans la table sans supprimer les lignes existantes. L’insertion n’est pas atomique, comme pour une requête `INSERT INTO ... SELECT` classique.
* Sinon, chaque rafraîchissement remplace atomiquement le contenu précédent de la table.

Différences par rapport aux vues matérialisées classiques non actualisables :

* Pas de déclencheur d’insertion. Lorsque de nouvelles données sont insérées dans la table spécifiée dans `SELECT`, elles ne sont *pas* automatiquement propagées vers la vue matérialisée actualisable. À la place, l’insertion des données n’a lieu que lors des rafraîchissements périodiques ou manuels.
* Aucune restriction sur la requête `SELECT`. Les fonctions de table (par ex. `url()`), les vues, UNION et JOIN sont tous autorisés.

<Note>
  Les paramètres de la partie `REFRESH ... SETTINGS` de la requête sont des paramètres de rafraîchissement (par ex. `refresh_retries`), distincts des paramètres classiques (par ex. `max_threads`). Les paramètres classiques peuvent être spécifiés à l’aide de `SETTINGS` à la fin de la requête.
</Note>

<div id="refresh-schedule">
  ### Planification du rafraîchissement
</div>

Exemples de planifications de rafraîchissement :

```sql theme={null}
REFRESH EVERY 1 DAY -- every day, at midnight (UTC)
REFRESH EVERY 1 MONTH -- on 1st day of every month, at midnight
REFRESH EVERY 1 MONTH OFFSET 5 DAY 2 HOUR -- on 6th day of every month, at 2:00 am
REFRESH EVERY 2 WEEK OFFSET 5 DAY 15 HOUR 10 MINUTE -- every other Saturday, at 3:10 pm
REFRESH EVERY 30 MINUTE -- at 00:00, 00:30, 01:00, 01:30, etc
REFRESH AFTER 30 MINUTE -- 30 minutes after the previous refresh completes, no alignment with time of day
-- REFRESH AFTER 1 HOUR OFFSET 1 MINUTE -- syntax error, OFFSET is not allowed with AFTER
REFRESH EVERY 1 WEEK 2 DAYS -- every 9 days, not on any particular day of the week or month;
                            -- specifically, when day number (since 1969-12-29) is divisible by 9
REFRESH EVERY 5 MONTHS -- every 5 months, different months each year (as 12 is not divisible by 5);
                       -- specifically, when month number (since 1970-01) is divisible by 5
```

`RANDOMIZE FOR` ajuste aléatoirement le moment de chaque actualisation, par exemple :

```sql theme={null}
REFRESH EVERY 1 DAY OFFSET 2 HOUR RANDOMIZE FOR 1 HOUR -- every day at random time between 01:30 and 02:30
```

Au plus un seul rafraîchissement peut être en cours à la fois pour une vue donnée. Par exemple, si le rafraîchissement d’une vue avec `REFRESH EVERY 1 MINUTE` prend 2 minutes, elle ne sera rafraîchie que toutes les 2 minutes. Si elle devient ensuite plus rapide et commence à se rafraîchir en 10 secondes, elle reviendra à un rafraîchissement toutes les minutes. (En particulier, elle ne se rafraîchira pas toutes les 10 secondes pour rattraper un éventuel retard de rafraîchissements manqués : il n’existe pas de tel retard.)

En général, le premier rafraîchissement démarre immédiatement après la création de la vue matérialisée : le temps écoulé depuis le dernier rafraîchissement est infini, donc toute planification indique qu’il faut la rafraîchir immédiatement. Si `EMPTY` est spécifié, ce rafraîchissement initial est ignoré, et le premier rafraîchissement a lieu à l’heure planifiée suivante ; par exemple, pour `EVERY 1 HOUR`, le premier rafraîchissement aura lieu à la fin de l’heure en cours.

<div id="in-replicated-db">
  ### Dans une base de données Replicated
</div>

Si la vue matérialisée actualisable se trouve dans une [base de données Replicated](/fr/reference/engines/database-engines/replicated), les répliques se coordonnent entre elles afin qu'une seule réplique effectue le rafraîchissement à chaque échéance planifiée. Le moteur de table [ReplicatedMergeTree](/fr/reference/engines/table-engines/mergetree-family/replication) est requis afin que toutes les répliques voient les données produites par le rafraîchissement.

En mode `APPEND`, la coordination peut être désactivée avec `SETTINGS all_replicas = 1`. Les répliques effectuent alors les rafraîchissements indépendamment les unes des autres. Dans ce cas, ReplicatedMergeTree n'est pas requis.

En mode non-`APPEND`, seul le rafraîchissement coordonné est pris en charge. Pour un fonctionnement non coordonné, utilisez la base de données `Atomic` et la requête `CREATE ... ON CLUSTER` pour créer des vues matérialisées actualisables sur toutes les répliques.

La coordination s'effectue via Keeper. Le chemin du znode est déterminé par le paramètre serveur [default\_replica\_path](/fr/reference/settings/server-settings/settings#default_replica_path).

<div id="refresh-dependencies">
  ### Dépendances d’actualisation
</div>

`DEPENDS ON` synchronise l’actualisation de différentes tables :

```sql theme={null}
CREATE MATERIALIZED VIEW dependent REFRESH EVERY 1 HOUR DEPENDS ON dependency [...]
```

L’actualisation de la vue dépendante ne démarrera qu’une fois l’actualisation de toutes les vues dont elle dépend terminée.

Pour actualiser immédiatement après l’actualisation d’une autre vue :

```sql theme={null}
CREATE MATERIALIZED VIEW dependent REFRESH AFTER 0 SECOND DEPENDS ON dependency [...]
```

Ou, de façon équivalente :

```sql theme={null}
CREATE MATERIALIZED VIEW dependent REFRESH DEPENDS ON dependency [...]
```

<Note>
  `DEPENDS ON` fonctionne uniquement entre des vues matérialisées actualisables. En particulier, si la vue dont elle dépend utilise `TO <table>`, veillez à utiliser le nom de la vue plutôt que celui de la table. Si la liste `DEPENDS ON` contient une table ordinaire, une vue non actualisable ou une faute de frappe, la vue ne sera jamais rafraîchie et affichera l’état `MissingDependencies` dans `system.view_refreshes`. Les dépendances peuvent être modifiées ou supprimées à l’aide de `ALTER` ; voir [Modification des paramètres de rafraîchissement](#changing-refresh-parameters).
</Note>

<div id="using-depends-on-for-consistent-propagation-latency">
  #### Utilisation de DEPENDS ON pour une latence de propagation cohérente
</div>

Si les deux vues utilisent `REFRESH EVERY` avec la même période, la dépendance s’applique à chaque créneau temporel.

Par exemple, supposons que les vues X et Y utilisent toutes deux `REFRESH EVERY 1 HOUR` et que Y lit les données de la table de sortie de X. Sans dépendance, Y verrait généralement les données du rafraîchissement de l’heure précédente de X. Avec `DEPENDS ON X`, le rafraîchissement de 11:00 de Y ne démarrera qu’une fois celui de 11:00 de X terminé.

```text theme={null}
           10:00            11:00            12:00
           │                │                │
  X:        [run]┐           [run]┐           [run]┐
                 │                │                │
  Y:             └►[run]          └►[run]          └►[run]
```

La dépendance comme l’élément dépendant peuvent chacun sauter des créneaux temporels de manière indépendante si les actualisations durent plus longtemps que la période d’actualisation. Rien ne garantit que l’élément dépendant s’actualise exactement une fois pour chaque actualisation de la dépendance.

```text theme={null}
           10:00          11:00          12:00          13:00
           │              │              │              |
  X:        [run]┐         [run]┐         [run]┐         [run]┐
                 │              └────┐    (Y skips 12:00)     └───┐
  Y:             └►[10:00 ru------un]└►[11:00 ru---------------un]└►[13:00 run]
```

<div id="using-depends-on-for-batched-stream-processing">
  #### Utilisation de DEPENDS ON pour le traitement de flux par lots
</div>

Si `REFRESH EVERY` n’est pas utilisé, la vue dépendante X se rafraîchit si toutes ses dépendances ont été rafraîchies au moins une fois depuis le dernier rafraîchissement de X. `REFRESH AFTER T` ajoute un délai : la vue dépendante commencera à se rafraîchir T unités de temps après qu’une dépendance a terminé un rafraîchissement.

Les dépendances circulaires sont autorisées et utiles. Considérez ce graphe de vues matérialisées actualisables :

1. X prend un lot de lignes d’un flux et les place dans une table.
2. Ensuite, Y et Z lisent tous deux dans cette table, effectuent des agrégations différentes et ajoutent les résultats à d’autres tables.
3. Une fois le lot entièrement traité, X prend le lot suivant, et le cycle se répète.

```text theme={null}
            source
               │
               ▼
          ┌─────────┐
     ┌───►│    X    │◄───┐
     │    └──┬───┬──┘    │
  DEPENDS    │   │    DEPENDS
    ON       ▼   ▼      ON
     │      ┌─┐ ┌─┐      │
     └──────┤Y│ │Z├──────┘
            └─┘ └─┘
```

Exemple complet :

```sql theme={null}
CREATE TABLE current_batch (t UInt64, v Int64) ENGINE ReplicatedMergeTree ORDER BY t;
CREATE TABLE batch_log (max_t UInt64, n Int64, v_sum Int64, processed_at DateTime64) ENGINE ReplicatedMergeTree ORDER BY max_t;
CREATE TABLE stats (h UInt64, n UInt64) ENGINE ReplicatedSummingMergeTree ORDER BY h;

-- (system.numbers stands in for a data source with monotonically increasing timestamps or sequence numbers)
CREATE MATERIALIZED VIEW current_batch_v REFRESH EVERY 10 SECOND DEPENDS ON batch_log_v, stats_v TO current_batch AS SELECT number as t, number * 10 as v FROM system.numbers WHERE number > (SELECT max(max_t) FROM batch_log) LIMIT 100;

CREATE MATERIALIZED VIEW batch_log_v REFRESH DEPENDS ON current_batch_v APPEND TO batch_log AS SELECT max(t) as max_t, count() as n, sum(v) as v_sum, now64() as processed_at FROM current_batch;

CREATE MATERIALIZED VIEW stats_v REFRESH DEPENDS ON current_batch_v APPEND TO stats AS SELECT cityHash64(v) % 20 as h, count() as n FROM current_batch GROUP BY h;

-- Must trigger initial refresh manually.
SYSTEM REFRESH VIEW current_batch_v;
```

Les chaînes plus longues fonctionnent également.

Cela ne fonctionne correctement que lorsque la coordination du rafraîchissement est activée, c’est-à-dire lorsque les vues se trouvent dans une base de données Replicated ou Shared database. Sans coordination, le redémarrage du serveur interrompt le cycle, ce qui nécessite un `SYSTEM REFRESH VIEW` manuel après chaque redémarrage, plutôt qu’une seule fois après la création des vues.

<div id="refresh-settings">
  ### Paramètres de rafraîchissement
</div>

Paramètres de rafraîchissement disponibles :

* `refresh_retries` - Nombre de tentatives en cas d’échec de la requête de rafraîchissement avec une exception. Si toutes les tentatives échouent, le système passe à l’heure de rafraîchissement planifiée suivante. 0 signifie aucune nouvelle tentative, -1 signifie un nombre infini de tentatives. Par défaut : 2.
* `refresh_retry_initial_backoff_ms` - Délai avant la première nouvelle tentative, si `refresh_retries` n’est pas égal à zéro. Chaque tentative suivante double le délai, jusqu’à `refresh_retry_max_backoff_ms`. Par défaut : 100 ms.
* `refresh_retry_max_backoff_ms` - Limite de la croissance exponentielle du délai entre les tentatives de rafraîchissement. Par défaut : 60000 ms (1 minute).
* `all_replicas` - Dans une [base de données Replicated](/fr/reference/engines/database-engines/replicated) avec `APPEND`, contrôle si toutes les répliques se rafraîchissent indépendamment ou si une seule réplique se rafraîchit à chaque heure planifiée. Ne peut pas être modifié après la création de la vue. Par défaut : `false`.

<div id="changing-refresh-parameters">
  ### Modification des paramètres de rafraîchissement
</div>

Les paramètres de rafraîchissement d’une vue matérialisée actualisable existante peuvent être modifiés à l’aide de [`ALTER TABLE ... MODIFY REFRESH`](/fr/reference/statements/alter/view#alter-table--modify-refresh-statement) :

```sql theme={null}
ALTER TABLE [db.]name MODIFY REFRESH EVERY|AFTER ... [RANDOMIZE FOR ...] [DEPENDS ON ...] [SETTINGS ...]
```

La planification (`EVERY` ou `AFTER`) est obligatoire : l’instruction remplace toujours *tous* les paramètres de rafraîchissement — la planification, `RANDOMIZE FOR`, `DEPENDS ON` et les paramètres de rafraîchissement — par ceux qui sont spécifiés. Tout élément omis est réinitialisé à sa valeur par défaut (paramètres) ou supprimé (dépendances, randomisation).

<Note>
  * Pour modifier uniquement les paramètres de rafraîchissement (par ex. `refresh_retries`), répétez la planification existante :

    ```sql theme={null}
    ALTER TABLE rmv MODIFY REFRESH EVERY 1 HOUR SETTINGS refresh_retries = 5;
    ```

  * `ALTER TABLE ... MODIFY SETTING refresh_retries = ...` n’est pas pris en charge pour les vues matérialisées ; vous devez passer par `MODIFY REFRESH`.

  * L’ajout ou la suppression de `APPEND` n’est pas pris en charge.

  * Le paramètre `all_replicas` ne peut pas être modifié après la création.
</Note>

Exemples :

```sql theme={null}
-- Change the schedule, drop existing settings and dependencies.
ALTER TABLE rmv MODIFY REFRESH EVERY 30 MINUTE;

-- Change the schedule and tune retry behavior.
ALTER TABLE rmv MODIFY REFRESH EVERY 30 MINUTE
SETTINGS refresh_retries = 5,
         refresh_retry_initial_backoff_ms = 500,
         refresh_retry_max_backoff_ms = 60000;

-- Keep the dependency while changing the period.
ALTER TABLE rmv MODIFY REFRESH EVERY 6 HOUR DEPENDS ON other_rmv;

-- Drop the dependency by omitting `DEPENDS ON`.
ALTER TABLE rmv MODIFY REFRESH EVERY 6 HOUR;
```

<div id="other-operations">
  ### Autres opérations
</div>

L’état de toutes les vues matérialisées actualisables est disponible dans la table [`system.view_refreshes`](/fr/reference/system-tables/view_refreshes). Elle contient notamment la progression du rafraîchissement (s’il est en cours), la date et l’heure du dernier et du prochain rafraîchissement, ainsi que le message d’exception si un rafraîchissement a échoué.

Pour arrêter, démarrer, déclencher ou annuler manuellement des rafraîchissements, utilisez [`SYSTEM STOP|START|REFRESH|WAIT|CANCEL VIEW`](/fr/reference/statements/system#managing-refreshable-materialized-views).

Pour attendre la fin d’un rafraîchissement, utilisez [`SYSTEM WAIT VIEW`](/fr/reference/statements/system#wait-view). C’est notamment utile pour attendre le rafraîchissement initial après la création d’une vue.

<Note>
  Fait amusant : la requête de rafraîchissement peut lire dans la vue en cours de rafraîchissement et voir la version des données antérieure au rafraîchissement. Cela signifie que vous pouvez implémenter le jeu de la vie de Conway : [https://pastila.nl/?00021a4b/d6156ff819c83d490ad2dcec05676865#O0LGWTO7maUQIA4AcGUtlA==](https://pastila.nl/?00021a4b/d6156ff819c83d490ad2dcec05676865#O0LGWTO7maUQIA4AcGUtlA==)
</Note>

<div id="window-view">
  ## Window View
</div>

<Info>
  Il s'agit d'une fonctionnalité expérimentale qui pourra évoluer de manière non compatible avec les versions antérieures dans les versions ultérieures. Pour utiliser les window views et la requête `WATCH`, activez le paramètre [allow\_experimental\_window\_view](/fr/reference/settings/session-settings#allow_experimental_window_view). Saisissez la commande `set allow_experimental_window_view = 1`.
</Info>

```sql theme={null}
CREATE WINDOW VIEW [IF NOT EXISTS] [db.]table_name [TO [db.]table_name] [INNER ENGINE engine] [ENGINE engine] [WATERMARK strategy] [ALLOWED_LATENESS interval_function] [POPULATE]
AS SELECT ...
GROUP BY time_window_function
[COMMENT 'comment']
```

La window view peut agréger les données par fenêtre temporelle et produire les résultats lorsque la fenêtre est prête à émettre. Elle stocke les résultats d'agrégation partiels dans une table interne (ou spécifiée) afin de réduire la latence, et peut envoyer le résultat du traitement vers une table spécifiée ou des notifications à l'aide de la requête WATCH.

La création d'une window view est similaire à celle d'une `MATERIALIZED VIEW`. Une window view nécessite un moteur de stockage interne pour stocker les données intermédiaires. Le stockage interne peut être spécifié à l'aide de la clause `INNER ENGINE` ; la window view utilisera `AggregatingMergeTree` comme moteur interne par défaut.

Lors de la création d'une window view sans `TO [db].[table]`, vous devez spécifier `ENGINE` – le moteur de table utilisé pour stocker les données.

<div id="time-window-functions">
  ### Fonctions de fenêtre temporelle
</div>

Les [fonctions de fenêtre temporelle](/fr/reference/functions/regular-functions/time-window-functions) servent à obtenir la borne inférieure et la borne supérieure de la fenêtre des enregistrements. La window view doit être utilisée avec une fonction de fenêtre temporelle.

<div id="time-attributes">
  ### ATTRIBUTS TEMPORELS
</div>

La window view prend en charge le **temps de traitement** et le **temps d’événement**.

Le **temps de traitement** permet à la window view de produire des résultats en fonction de l’heure de la machine locale et est utilisé par défaut. C’est la notion du temps la plus simple, mais elle n’offre pas de déterminisme. L’attribut de temps de traitement peut être défini en affectant à `time_attr` de la fonction de fenêtre temporelle une colonne de table, ou en utilisant la fonction `now()`. La requête suivante crée une window view avec le temps de traitement.

```sql theme={null}
CREATE WINDOW VIEW wv AS SELECT count(number), tumbleStart(w_id) as w_start from date GROUP BY tumble(now(), INTERVAL '5' SECOND) as w_id
```

**Le temps d’événement** correspond au moment où chaque événement s'est produit sur l'appareil qui l'a généré. Ce temps est généralement intégré aux enregistrements au moment de leur création. Le traitement basé sur le temps d’événement permet d'obtenir des résultats cohérents, même en cas d'événements arrivant dans le désordre ou en retard. Window view prend en charge le traitement basé sur le temps d’événement à l'aide de la syntaxe `WATERMARK`.

Window view propose trois stratégies de watermark :

* `STRICTLY_ASCENDING` : émet un watermark correspondant à l'horodatage maximal observé jusqu'à présent. Les lignes dont l'horodatage est inférieur à l'horodatage maximal ne sont pas considérées comme en retard.
* `ASCENDING` : émet un watermark correspondant à l'horodatage maximal observé jusqu'à présent moins 1. Les lignes dont l'horodatage est égal ou inférieur à l'horodatage maximal ne sont pas considérées comme en retard.
* `BOUNDED` : WATERMARK=INTERVAL. Émet des watermarks correspondant à l'horodatage maximal observé moins le délai spécifié.

Les requêtes suivantes montrent des exemples de création d'une window view avec `WATERMARK` :

```sql theme={null}
CREATE WINDOW VIEW wv WATERMARK=STRICTLY_ASCENDING AS SELECT count(number) FROM date GROUP BY tumble(timestamp, INTERVAL '5' SECOND);
CREATE WINDOW VIEW wv WATERMARK=ASCENDING AS SELECT count(number) FROM date GROUP BY tumble(timestamp, INTERVAL '5' SECOND);
CREATE WINDOW VIEW wv WATERMARK=INTERVAL '3' SECOND AS SELECT count(number) FROM date GROUP BY tumble(timestamp, INTERVAL '5' SECOND);
```

Par défaut, la fenêtre sera déclenchée à l’arrivée du watermark, et les éléments arrivés après celui-ci seront ignorés. Window View prend en charge le traitement des événements en retard en définissant `ALLOWED_LATENESS=INTERVAL`. Voici un exemple de gestion du retard :

```sql theme={null}
CREATE WINDOW VIEW test.wv TO test.dst WATERMARK=ASCENDING ALLOWED_LATENESS=INTERVAL '2' SECOND AS SELECT count(a) AS count, tumbleEnd(wid) AS w_end FROM test.mt GROUP BY tumble(timestamp, INTERVAL '5' SECOND) AS wid;
```

Notez que les éléments émis lors d’un déclenchement tardif doivent être considérés comme des résultats mis à jour d’un calcul précédent. Au lieu de se déclencher à la fin des fenêtres, la window view se déclenche immédiatement à l’arrivée de l’événement tardif. Cela entraîne donc plusieurs résultats pour une même fenêtre. Les utilisateurs doivent tenir compte de ces résultats dupliqués ou les dédupliquer.

Vous pouvez modifier la requête `SELECT` spécifiée dans la window view à l’aide de l’instruction `ALTER TABLE ... MODIFY QUERY`. La structure de données résultant de la nouvelle requête `SELECT` doit être identique à celle de la requête `SELECT` d’origine, avec ou sans la clause `TO [db.]name`. Notez que les données de la fenêtre en cours seront perdues, car l’état intermédiaire ne peut pas être réutilisé.

<div id="monitoring-new-windows">
  ### Surveillance des nouvelles fenêtres
</div>

La window view prend en charge la requête [WATCH](/fr/reference/statements/watch) pour surveiller les modifications, ou vous pouvez utiliser la syntaxe `TO` pour écrire les résultats dans une table.

```sql theme={null}
WATCH [db.]window_view
[EVENTS]
[LIMIT n]
[FORMAT format]
```

Il est possible de spécifier un `LIMIT` pour définir le nombre de mises à jour à recevoir avant de mettre fin à la requête. La clause `EVENTS` permet d'obtenir une forme abrégée de la requête `WATCH` : au lieu du résultat de la requête, vous ne recevrez que son watermark le plus récent.

<div id="settings-1">
  ### Paramètres
</div>

* `window_view_clean_interval` : intervalle de nettoyage de la window view, en secondes, pour libérer les données obsolètes. Le système conserve les fenêtres qui n’ont pas encore été entièrement déclenchées en fonction de l’heure système ou de la configuration `WATERMARK`, et supprime les autres données.
* `window_view_heartbeat_interval` : intervalle de heartbeat, en secondes, indiquant que la requête watch est active.
* `wait_for_window_view_fire_signal_timeout` : délai d’attente du signal de déclenchement de la window view lors du traitement en temps d’événement.

<div id="example">
  ### Exemple
</div>

Supposons que nous devions compter le nombre de logs de clics toutes les 10 secondes dans une table de logs appelée `data`, dont la structure est la suivante :

```sql theme={null}
CREATE TABLE data ( `id` UInt64, `timestamp` DateTime) ENGINE = Memory;
```

Tout d’abord, nous créons une window view avec une fenêtre fixe de 10 secondes :

```sql theme={null}
CREATE WINDOW VIEW wv as select count(id), tumbleStart(w_id) as window_start from data group by tumble(timestamp, INTERVAL '10' SECOND) as w_id
```

Ensuite, nous utilisons la requête `WATCH` pour obtenir les résultats.

```sql theme={null}
WATCH wv
```

Lorsque des logs sont insérés dans la table `data`,

```sql theme={null}
INSERT INTO data VALUES(1,now())
```

La requête `WATCH` devrait afficher les résultats comme ceci :

```text theme={null}
┌─count(id)─┬────────window_start─┐
│         1 │ 2020-01-14 16:56:40 │
└───────────┴─────────────────────┘
```

Sinon, nous pouvons envoyer la sortie vers une autre table à l’aide de la syntaxe `TO`.

```sql theme={null}
CREATE WINDOW VIEW wv TO dst AS SELECT count(id), tumbleStart(w_id) as window_start FROM data GROUP BY tumble(timestamp, INTERVAL '10' SECOND) as w_id
```

Vous trouverez d'autres exemples parmi les tests avec état de ClickHouse (ils y sont nommés `*window_view*`).

<div id="window-view-usage">
  ### Utilisation de Window View
</div>

La fonctionnalité window view est utile dans les scénarios suivants :

* **Surveillance** : agréger et calculer les métriques des logs au fil du temps, puis envoyer les résultats vers une table cible. Le tableau de bord peut utiliser la table cible comme table source.
* **Analyse** : agréger et prétraiter automatiquement les données dans la fenêtre temporelle. Cela peut être utile lors de l’analyse d’un grand nombre de logs. Ce prétraitement élimine les calculs répétés dans plusieurs requêtes et réduit la latence des requêtes.

<div id="related-content">
  ## Contenu associé
</div>

* Blog : [Travailler avec des données de séries temporelles dans ClickHouse](https://clickhouse.com/blog/working-with-time-series-data-and-functions-ClickHouse)
* Blog : [Créer une solution d’observabilité avec ClickHouse - Partie 2 - Traces](https://clickhouse.com/blog/storing-traces-and-spans-open-telemetry-in-clickhouse)

<div id="temporary-views">
  ## Vues temporaires
</div>

ClickHouse prend en charge les **vues temporaires** avec les caractéristiques suivantes (comme pour les tables temporaires, le cas échéant) :

* **Durée de vie de la session**
  Une vue temporaire n’existe que pendant la session en cours. Elle est supprimée automatiquement à la fin de la session.

* **Aucune base de données**
  Vous **ne pouvez pas** qualifier une vue temporaire avec un nom de base de données. Elle existe en dehors des bases de données (dans l’espace de noms de la session).

* **Non répliqué / pas de ON CLUSTER**
  Les objets temporaires sont locaux à la session et **ne peuvent pas** être créés avec `ON CLUSTER`.

* **Résolution des noms**
  Si un objet temporaire (table ou vue) porte le même nom qu’un objet persistant et qu’une requête fait référence à ce nom **sans** base de données, c’est l’objet **temporaire** qui est utilisé.

* **Objet logique (pas de stockage)**
  Une vue temporaire stocke uniquement son texte `SELECT` (en utilisant le moteur `View` en interne). Elle ne conserve pas les données et n’accepte pas `INSERT`.

* **Clause ENGINE**
  Vous **n’avez pas** besoin de spécifier `ENGINE` ; s’il est fourni sous la forme `ENGINE = View`, il est ignoré ou traité comme la même vue logique.

* **Sécurité / privilèges**
  La création d’une vue temporaire nécessite le privilège `CREATE TEMPORARY VIEW`, implicitement accordé par `CREATE VIEW`.

* **SHOW CREATE**
  Utilisez `SHOW CREATE TEMPORARY VIEW view_name;` pour afficher le DDL d’une vue temporaire.

<div id="temporary-views-syntax">
  ### Syntaxe
</div>

```sql theme={null}
CREATE TEMPORARY VIEW [IF NOT EXISTS] view_name AS <select_query>
```

`OR REPLACE` n’est **pas** pris en charge pour les vues temporaires (comme pour les tables temporaires). Si vous devez « remplacer » une vue temporaire, supprimez-la, puis recréez-la.

<div id="examples">
  ### Exemples
</div>

Créez une table source temporaire, ainsi qu’une vue temporaire basée sur celle-ci :

```sql theme={null}
CREATE TEMPORARY TABLE t_src (id UInt32, val String);
INSERT INTO t_src VALUES (1, 'a'), (2, 'b');

CREATE TEMPORARY VIEW tview AS
SELECT id, upper(val) AS u
FROM t_src
WHERE id <= 2;

SELECT * FROM tview ORDER BY id;
```

Affichez son DDL :

```sql theme={null}
SHOW CREATE TEMPORARY VIEW tview;
```

Supprimez-la :

```sql theme={null}
DROP TEMPORARY VIEW IF EXISTS tview;  -- temporary views are dropped with TEMPORARY TABLE syntax
```

<div id="temporary-views-limitations">
  ### Restrictions / limites
</div>

* `CREATE OR REPLACE TEMPORARY VIEW ...` → **non autorisé** (utilisez `DROP` + `CREATE`).
* `CREATE TEMPORARY MATERIALIZED VIEW ...` / `WINDOW VIEW` → **non autorisé**.
* `CREATE TEMPORARY VIEW db.view AS ...` → **non autorisé** (pas de qualificatif de base de données).
* `CREATE TEMPORARY VIEW view ON CLUSTER 'name' AS ...` → **non autorisé** (les objets temporaires sont locaux à la session).
* `POPULATE`, `REFRESH`, `TO [db.table]`, les moteurs internes et toutes les clauses propres aux MV → **non applicables** aux vues temporaires.

<div id="temporary-views-distributed-notes">
  ### Remarques sur les requêtes distribuées
</div>

Une **vue** temporaire n’est qu’une définition ; il n’y a donc aucune donnée à faire circuler. Si votre vue temporaire fait référence à des **tables** temporaires (par ex., `Memory`), leurs données peuvent être envoyées vers des serveurs distants lors de l’exécution distribuée des requêtes, de la même manière que pour les tables temporaires.

<div id="temporary-views-distributed-example">
  #### Exemple
</div>

```sql theme={null}
-- A session-scoped, in-memory table
CREATE TEMPORARY TABLE temp_ids (id UInt64) ENGINE = Memory;

INSERT INTO temp_ids VALUES (1), (5), (42);

-- A session-scoped view over the temp table (purely logical)
CREATE TEMPORARY VIEW v_ids AS
SELECT id FROM temp_ids;

-- Replace 'test' with your cluster name.
-- GLOBAL JOIN forces ClickHouse to *ship* the small join-side (temp_ids via v_ids)
-- to every remote server that executes the left side.
SELECT count()
FROM cluster('test', system.numbers) AS n
GLOBAL ANY INNER JOIN v_ids USING (id)
WHERE n.number < 100;

```
