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

> Documentation du type de données Dynamic dans ClickHouse, qui peut stocker des valeurs de types différents dans une seule colonne

# Dynamic

Ce type permet de stocker des valeurs de n’importe quel type sans devoir toutes les connaître à l’avance.

Pour déclarer une colonne de type `Dynamic`, utilisez la syntaxe suivante :

```sql theme={null}
<column_name> Dynamic(max_types=N)
```

Où `N` est un paramètre facultatif compris entre `0` et `254`, indiquant combien de types de données différents peuvent être stockés sous forme de sous-colonnes distinctes à l’intérieur d’une colonne de type `Dynamic` dans un seul bloc de données stocké séparément (par exemple dans une seule partie de données pour une table MergeTree). Si cette limite est dépassée, toutes les valeurs avec de nouveaux types seront stockées ensemble dans une structure de données partagée spéciale sous forme binaire. La valeur par défaut de `max_types` est `32`.

<div id="creating-dynamic">
  ## Création de Dynamic
</div>

Utilisation du type `Dynamic` dans la définition d’une colonne d’une table :

```sql theme={null}
CREATE TABLE test (d Dynamic) ENGINE = Memory;
INSERT INTO test VALUES (NULL), (42), ('Hello, World!'), ([1, 2, 3]);
SELECT d, dynamicType(d) FROM test;
```

```text theme={null}
┌─d─────────────┬─dynamicType(d)─┐
│ ᴺᵁᴸᴸ          │ None           │
│ 42            │ Int64          │
│ Hello, World! │ String         │
│ [1,2,3]       │ Array(Int64)   │
└───────────────┴────────────────┘
```

Utilisation de CAST avec une colonne ordinaire :

```sql theme={null}
SELECT 'Hello, World!'::Dynamic AS d, dynamicType(d);
```

```text theme={null}
┌─d─────────────┬─dynamicType(d)─┐
│ Hello, World! │ String         │
└───────────────┴────────────────┘
```

Utilisation de CAST sur la colonne `Variant` :

```sql theme={null}
SET use_variant_as_common_type = 1;
SELECT multiIf((number % 3) = 0, number, (number % 3) = 1, range(number + 1), NULL)::Dynamic AS d, dynamicType(d) FROM numbers(3)
```

```text theme={null}
┌─d─────┬─dynamicType(d)─┐
│ 0     │ UInt64         │
│ [0,1] │ Array(UInt64)  │
│ ᴺᵁᴸᴸ  │ None           │
└───────┴────────────────┘
```

<div id="reading-dynamic-nested-types-as-subcolumns">
  ## Lecture des types imbriqués `Dynamic` en tant que sous-colonnes
</div>

Le type `Dynamic` permet de lire un type imbriqué unique à partir d’une colonne `Dynamic` en utilisant le nom du type comme sous-colonne.
Ainsi, si vous avez la colonne `d Dynamic`, vous pouvez lire une sous-colonne de n’importe quel type valide `T` à l’aide de la syntaxe `d.T`.
Cette sous-colonne aura le type `Nullable(T)` si `T` peut être contenu dans `Nullable`, et sinon le type `T`. Elle aura la même taille que la colonne `Dynamic` d’origine et contiendra des valeurs `NULL` (ou des valeurs vides si `T` ne peut pas être contenu dans `Nullable`)
dans toutes les lignes où la colonne `Dynamic` d’origine n’est pas de type `T`.

Les sous-colonnes `Dynamic` peuvent également être lues à l’aide de la fonction `dynamicElement(dynamic_column, type_name)`.

Exemples :

```sql theme={null}
CREATE TABLE test (d Dynamic) ENGINE = Memory;
INSERT INTO test VALUES (NULL), (42), ('Hello, World!'), ([1, 2, 3]);
SELECT d, dynamicType(d), d.String, d.Int64, d.`Array(Int64)`, d.Date, d.`Array(String)` FROM test;
```

```text theme={null}
┌─d─────────────┬─dynamicType(d)─┬─d.String──────┬─d.Int64─┬─d.Array(Int64)─┬─d.Date─┬─d.Array(String)─┐
│ ᴺᵁᴸᴸ          │ None           │ ᴺᵁᴸᴸ          │    ᴺᵁᴸᴸ │ []             │   ᴺᵁᴸᴸ │ []              │
│ 42            │ Int64          │ ᴺᵁᴸᴸ          │      42 │ []             │   ᴺᵁᴸᴸ │ []              │
│ Hello, World! │ String         │ Hello, World! │    ᴺᵁᴸᴸ │ []             │   ᴺᵁᴸᴸ │ []              │
│ [1,2,3]       │ Array(Int64)   │ ᴺᵁᴸᴸ          │    ᴺᵁᴸᴸ │ [1,2,3]        │   ᴺᵁᴸᴸ │ []              │
└───────────────┴────────────────┴───────────────┴─────────┴────────────────┴────────┴─────────────────┘
```

```sql theme={null}
SELECT toTypeName(d.String), toTypeName(d.Int64), toTypeName(d.`Array(Int64)`), toTypeName(d.Date), toTypeName(d.`Array(String)`)  FROM test LIMIT 1;
```

```text theme={null}
┌─toTypeName(d.String)─┬─toTypeName(d.Int64)─┬─toTypeName(d.Array(Int64))─┬─toTypeName(d.Date)─┬─toTypeName(d.Array(String))─┐
│ Nullable(String)     │ Nullable(Int64)     │ Array(Int64)               │ Nullable(Date)     │ Array(String)               │
└──────────────────────┴─────────────────────┴────────────────────────────┴────────────────────┴─────────────────────────────┘
```

````sql theme={null}
SELECT d, dynamicType(d), dynamicElement(d, 'String'), dynamicElement(d, 'Int64'), dynamicElement(d, 'Array(Int64)'), dynamicElement(d, 'Date'), dynamicElement(d, 'Array(String)') FROM test;```
````

```text theme={null}
┌─d─────────────┬─dynamicType(d)─┬─dynamicElement(d, 'String')─┬─dynamicElement(d, 'Int64')─┬─dynamicElement(d, 'Array(Int64)')─┬─dynamicElement(d, 'Date')─┬─dynamicElement(d, 'Array(String)')─┐
│ ᴺᵁᴸᴸ          │ None           │ ᴺᵁᴸᴸ                        │                       ᴺᵁᴸᴸ │ []                                │                      ᴺᵁᴸᴸ │ []                                 │
│ 42            │ Int64          │ ᴺᵁᴸᴸ                        │                         42 │ []                                │                      ᴺᵁᴸᴸ │ []                                 │
│ Hello, World! │ String         │ Hello, World!               │                       ᴺᵁᴸᴸ │ []                                │                      ᴺᵁᴸᴸ │ []                                 │
│ [1,2,3]       │ Array(Int64)   │ ᴺᵁᴸᴸ                        │                       ᴺᵁᴸᴸ │ [1,2,3]                           │                      ᴺᵁᴸᴸ │ []                                 │
└───────────────┴────────────────┴─────────────────────────────┴────────────────────────────┴───────────────────────────────────┴───────────────────────────┴────────────────────────────────────┘
```

Pour savoir quelle variante est stockée dans chaque ligne, vous pouvez utiliser la fonction `dynamicType(dynamic_column)`. Elle renvoie une `String` contenant, pour chaque ligne, le nom du type de la valeur (ou `'None'` si la ligne est `NULL`).

Exemple :

```sql theme={null}
CREATE TABLE test (d Dynamic) ENGINE = Memory;
INSERT INTO test VALUES (NULL), (42), ('Hello, World!'), ([1, 2, 3]);
SELECT dynamicType(d) FROM test;
```

```text theme={null}
┌─dynamicType(d)─┐
│ None           │
│ Int64          │
│ String         │
│ Array(Int64)   │
└────────────────┘
```

<div id="conversion-between-dynamic-column-and-other-columns">
  ## Conversion entre une colonne Dynamic et d'autres colonnes
</div>

Il existe 4 conversions possibles avec une colonne `Dynamic`.

<div id="converting-an-ordinary-column-to-a-dynamic-column">
  ### Conversion d’une colonne ordinaire en colonne Dynamic
</div>

```sql theme={null}
SELECT 'Hello, World!'::Dynamic AS d, dynamicType(d);
```

```text theme={null}
┌─d─────────────┬─dynamicType(d)─┐
│ Hello, World! │ String         │
└───────────────┴────────────────┘
```

<div id="converting-a-string-column-to-a-dynamic-column-through-parsing">
  ### Conversion d'une colonne String en colonne Dynamic par analyse
</div>

Pour analyser des valeurs de type `Dynamic` à partir d'une colonne `String`, vous pouvez activer le paramètre `cast_string_to_dynamic_use_inference` :

```sql theme={null}
SET cast_string_to_dynamic_use_inference = 1;
SELECT CAST(materialize(map('key1', '42', 'key2', 'true', 'key3', '2020-01-01')), 'Map(String, Dynamic)') as map_of_dynamic, mapApply((k, v) -> (k, dynamicType(v)), map_of_dynamic) as map_of_dynamic_types;
```

```text theme={null}
┌─map_of_dynamic──────────────────────────────┬─map_of_dynamic_types─────────────────────────┐
│ {'key1':42,'key2':true,'key3':'2020-01-01'} │ {'key1':'Int64','key2':'Bool','key3':'Date'} │
└─────────────────────────────────────────────┴──────────────────────────────────────────────┘
```

<div id="converting-a-dynamic-column-to-an-ordinary-column">
  ### Conversion d’une colonne Dynamic en colonne ordinaire
</div>

Il est possible de convertir une colonne `Dynamic` en colonne ordinaire. Dans ce cas, tous les types imbriqués sont convertis vers un type de destination :

```sql theme={null}
CREATE TABLE test (d Dynamic) ENGINE = Memory;
INSERT INTO test VALUES (NULL), (42), ('42.42'), (true), ('e10');
SELECT d::Nullable(Float64) FROM test;
```

```text theme={null}
┌─CAST(d, 'Nullable(Float64)')─┐
│                         ᴺᵁᴸᴸ │
│                           42 │
│                        42.42 │
│                            1 │
│                            0 │
└──────────────────────────────┘
```

<div id="converting-a-variant-column-to-dynamic-column">
  ### Conversion d’une colonne de type Variant en colonne de type Dynamic
</div>

```sql theme={null}
CREATE TABLE test (v Variant(UInt64, String, Array(UInt64))) ENGINE = Memory;
INSERT INTO test VALUES (NULL), (42), ('String'), ([1, 2, 3]);
SELECT v::Dynamic AS d, dynamicType(d) FROM test; 
```

```text theme={null}
┌─d───────┬─dynamicType(d)─┐
│ ᴺᵁᴸᴸ    │ None           │
│ 42      │ UInt64         │
│ String  │ String         │
│ [1,2,3] │ Array(UInt64)  │
└─────────┴────────────────┘
```

<div id="converting-a-dynamicmax_typesn-column-to-another-dynamicmax_typesk">
  ### Conversion d’une colonne Dynamic(max\_types=N) en colonne Dynamic(max\_types=K)
</div>

Si `K >= N`, les données ne changent pas pendant la conversion :

```sql theme={null}
CREATE TABLE test (d Dynamic(max_types=3)) ENGINE = Memory;
INSERT INTO test VALUES (NULL), (42), (43), ('42.42'), (true);
SELECT d::Dynamic(max_types=5) as d2, dynamicType(d2) FROM test;
```

```text theme={null}
┌─d─────┬─dynamicType(d)─┐
│ ᴺᵁᴸᴸ  │ None           │
│ 42    │ Int64          │
│ 43    │ Int64          │
│ 42.42 │ String         │
│ true  │ Bool           │
└───────┴────────────────┘
```

Si `K < N`, alors les valeurs des types les moins fréquents seront insérées dans une unique sous-colonne spéciale, tout en restant accessibles :

```text theme={null}
CREATE TABLE test (d Dynamic(max_types=4)) ENGINE = Memory;
INSERT INTO test VALUES (NULL), (42), (43), ('42.42'), (true), ([1, 2, 3]);
SELECT d, dynamicType(d), d::Dynamic(max_types=2) as d2, dynamicType(d2), isDynamicElementInSharedData(d2) FROM test;
```

```text theme={null}
┌─d───────┬─dynamicType(d)─┬─d2──────┬─dynamicType(d2)─┬─isDynamicElementInSharedData(d2)─┐
│ ᴺᵁᴸᴸ    │ None           │ ᴺᵁᴸᴸ    │ None            │ false                            │
│ 42      │ Int64          │ 42      │ Int64           │ false                            │
│ 43      │ Int64          │ 43      │ Int64           │ false                            │
│ 42.42   │ String         │ 42.42   │ String          │ false                            │
│ true    │ Bool           │ true    │ Bool            │ true                             │
│ [1,2,3] │ Array(Int64)   │ [1,2,3] │ Array(Int64)    │ true                             │
└─────────┴────────────────┴─────────┴─────────────────┴──────────────────────────────────┘
```

La fonction `isDynamicElementInSharedData` renvoie `true` pour les lignes stockées dans une structure de données partagée spéciale au sein de `Dynamic` et, comme on peut le voir, la colonne obtenue ne contient que 2 types qui ne sont pas stockés dans la structure de données partagée.

Si `K=0`, tous les types seront insérés dans une seule sous-colonne spéciale :

```text theme={null}
CREATE TABLE test (d Dynamic(max_types=4)) ENGINE = Memory;
INSERT INTO test VALUES (NULL), (42), (43), ('42.42'), (true), ([1, 2, 3]);
SELECT d, dynamicType(d), d::Dynamic(max_types=0) as d2, dynamicType(d2), isDynamicElementInSharedData(d2) FROM test;
```

```text theme={null}
┌─d───────┬─dynamicType(d)─┬─d2──────┬─dynamicType(d2)─┬─isDynamicElementInSharedData(d2)─┐
│ ᴺᵁᴸᴸ    │ None           │ ᴺᵁᴸᴸ    │ None            │ false                            │
│ 42      │ Int64          │ 42      │ Int64           │ true                             │
│ 43      │ Int64          │ 43      │ Int64           │ true                             │
│ 42.42   │ String         │ 42.42   │ String          │ true                             │
│ true    │ Bool           │ true    │ Bool            │ true                             │
│ [1,2,3] │ Array(Int64)   │ [1,2,3] │ Array(Int64)    │ true                             │
└─────────┴────────────────┴─────────┴─────────────────┴──────────────────────────────────┘
```

<div id="reading-dynamic-type-from-the-data">
  ## Lecture du type Dynamic à partir des données
</div>

Tous les formats texte (TSV, CSV, CustomSeparated, Values, JSONEachRow, etc.) prennent en charge la lecture du type `Dynamic`. Lors de l’analyse des données, ClickHouse essaie d’inférer le type de chaque valeur et de l’utiliser lors de l’insertion dans une colonne `Dynamic`.

Exemple :

```sql theme={null}
SELECT
    d,
    dynamicType(d),
    dynamicElement(d, 'String') AS str,
    dynamicElement(d, 'Int64') AS num,
    dynamicElement(d, 'Float64') AS float,
    dynamicElement(d, 'Date') AS date,
    dynamicElement(d, 'Array(Int64)') AS arr
FROM format(JSONEachRow, 'd Dynamic', $$
{"d" : "Hello, World!"},
{"d" : 42},
{"d" : 42.42},
{"d" : "2020-01-01"},
{"d" : [1, 2, 3]}
$$)
```

```text theme={null}
┌─d─────────────┬─dynamicType(d)─┬─str───────────┬──num─┬─float─┬───────date─┬─arr─────┐
│ Hello, World! │ String         │ Hello, World! │ ᴺᵁᴸᴸ │  ᴺᵁᴸᴸ │       ᴺᵁᴸᴸ │ []      │
│ 42            │ Int64          │ ᴺᵁᴸᴸ          │   42 │  ᴺᵁᴸᴸ │       ᴺᵁᴸᴸ │ []      │
│ 42.42         │ Float64        │ ᴺᵁᴸᴸ          │ ᴺᵁᴸᴸ │ 42.42 │       ᴺᵁᴸᴸ │ []      │
│ 2020-01-01    │ Date           │ ᴺᵁᴸᴸ          │ ᴺᵁᴸᴸ │  ᴺᵁᴸᴸ │ 2020-01-01 │ []      │
│ [1,2,3]       │ Array(Int64)   │ ᴺᵁᴸᴸ          │ ᴺᵁᴸᴸ │  ᴺᵁᴸᴸ │       ᴺᵁᴸᴸ │ [1,2,3] │
└───────────────┴────────────────┴───────────────┴──────┴───────┴────────────┴─────────┘
```

<div id="using-dynamic-type-in-functions">
  ## Utilisation du type Dynamic dans les fonctions
</div>

La plupart des fonctions acceptent des arguments de type `Dynamic`. Dans ce cas, la fonction est exécutée séparément sur chaque type de données interne stocké dans la colonne `Dynamic`.
Lorsque le type de résultat de la fonction dépend des types des arguments, le résultat d'une telle fonction exécutée avec des arguments `Dynamic` sera `Dynamic`. Lorsque le type de résultat de la fonction ne dépend pas des types des arguments, le résultat sera `Nullable(T)`, où `T` est le type de résultat habituel de cette fonction.

Exemples :

```sql theme={null}
CREATE TABLE test (d Dynamic) ENGINE=Memory;
INSERT INTO test VALUES (NULL), (1::Int8), (2::Int16), (3::Int32), (4::Int64);
```

```sql theme={null}
SELECT d, dynamicType(d) FROM test;
```

```text theme={null}
┌─d────┬─dynamicType(d)─┐
│ ᴺᵁᴸᴸ │ None           │
│ 1    │ Int8           │
│ 2    │ Int16          │
│ 3    │ Int32          │
│ 4    │ Int64          │
└──────┴────────────────┘
```

```sql theme={null}
SELECT d, d + 1 AS res, toTypeName(res), dynamicType(res) FROM test;
```

```text theme={null}
┌─d────┬─res──┬─toTypeName(res)─┬─dynamicType(res)─┐
│ ᴺᵁᴸᴸ │ ᴺᵁᴸᴸ │ Dynamic         │ None             │
│ 1    │ 2    │ Dynamic         │ Int16            │
│ 2    │ 3    │ Dynamic         │ Int32            │
│ 3    │ 4    │ Dynamic         │ Int64            │
│ 4    │ 5    │ Dynamic         │ Int64            │
└──────┴──────┴─────────────────┴──────────────────┘
```

```sql theme={null}
SELECT d, d + d AS res, toTypeName(res), dynamicType(res) FROM test;
```

```text theme={null}
┌─d────┬─res──┬─toTypeName(res)─┬─dynamicType(res)─┐
│ ᴺᵁᴸᴸ │ ᴺᵁᴸᴸ │ Dynamic         │ None             │
│ 1    │ 2    │ Dynamic         │ Int16            │
│ 2    │ 4    │ Dynamic         │ Int32            │
│ 3    │ 6    │ Dynamic         │ Int64            │
│ 4    │ 8    │ Dynamic         │ Int64            │
└──────┴──────┴─────────────────┴──────────────────┘
```

```sql theme={null}
SELECT d, d < 3 AS res, toTypeName(res) FROM test;
```

```text theme={null}
┌─d────┬──res─┬─toTypeName(res)─┐
│ ᴺᵁᴸᴸ │ ᴺᵁᴸᴸ │ Nullable(UInt8) │
│ 1    │    1 │ Nullable(UInt8) │
│ 2    │    1 │ Nullable(UInt8) │
│ 3    │    0 │ Nullable(UInt8) │
│ 4    │    0 │ Nullable(UInt8) │
└──────┴──────┴─────────────────┘
```

```sql theme={null}
SELECT d, exp2(d) AS res, toTypeName(res) FROM test;
```

```sql theme={null}
┌─d────┬──res─┬─toTypeName(res)───┐
│ ᴺᵁᴸᴸ │ ᴺᵁᴸᴸ │ Nullable(Float64) │
│ 1    │    2 │ Nullable(Float64) │
│ 2    │    4 │ Nullable(Float64) │
│ 3    │    8 │ Nullable(Float64) │
│ 4    │   16 │ Nullable(Float64) │
└──────┴──────┴───────────────────┘
```

```sql theme={null}
TRUNCATE TABLE test;
INSERT INTO test VALUES (NULL), ('str_1'), ('str_2');
SELECT d, dynamicType(d) FROM test;
```

```text theme={null}
┌─d─────┬─dynamicType(d)─┐
│ ᴺᵁᴸᴸ  │ None           │
│ str_1 │ String         │
│ str_2 │ String         │
└───────┴────────────────┘
```

```sql theme={null}
SELECT d, upper(d) AS res, toTypeName(res) FROM test;
```

```text theme={null}
┌─d─────┬─res───┬─toTypeName(res)──┐
│ ᴺᵁᴸᴸ  │ ᴺᵁᴸᴸ  │ Nullable(String) │
│ str_1 │ STR_1 │ Nullable(String) │
│ str_2 │ STR_2 │ Nullable(String) │
└───────┴───────┴──────────────────┘
```

```sql theme={null}
SELECT d, extract(d, '([0-3])') AS res, toTypeName(res) FROM test;
```

```text theme={null}
┌─d─────┬─res──┬─toTypeName(res)──┐
│ ᴺᵁᴸᴸ  │ ᴺᵁᴸᴸ │ Nullable(String) │
│ str_1 │ 1    │ Nullable(String) │
│ str_2 │ 2    │ Nullable(String) │
└───────┴──────┴──────────────────┘
```

```sql theme={null}
TRUNCATE TABLE test;
INSERT INTO test VALUES (NULL), ([1, 2]), ([3, 4]);
SELECT d, dynamicType(d) FROM test;
```

```text theme={null}
┌─d─────┬─dynamicType(d)─┐
│ ᴺᵁᴸᴸ  │ None           │
│ [1,2] │ Array(Int64)   │
│ [3,4] │ Array(Int64)   │
└───────┴────────────────┘
```

```sql theme={null}
SELECT d, d[1] AS res, toTypeName(res), dynamicType(res) FROM test;
```

```text theme={null}
┌─d─────┬─res──┬─toTypeName(res)─┬─dynamicType(res)─┐
│ ᴺᵁᴸᴸ  │ ᴺᵁᴸᴸ │ Dynamic         │ None             │
│ [1,2] │ 1    │ Dynamic         │ Int64            │
│ [3,4] │ 3    │ Dynamic         │ Int64            │
└───────┴──────┴─────────────────┴──────────────────┘
```

Si la fonction ne peut pas être exécutée sur un type donné de la colonne `Dynamic`, une exception sera levée :

```sql theme={null}
INSERT INTO test VALUES (42), (43), ('str_1');
SELECT d, dynamicType(d) FROM test;
```

```text theme={null}
┌─d─────┬─dynamicType(d)─┐
│ 42    │ Int64          │
│ 43    │ Int64          │
│ str_1 │ String         │
└───────┴────────────────┘
┌─d─────┬─dynamicType(d)─┐
│ ᴺᵁᴸᴸ  │ None           │
│ [1,2] │ Array(Int64)   │
│ [3,4] │ Array(Int64)   │
└───────┴────────────────┘
```

```sql theme={null}
SELECT d, d + 1 AS res, toTypeName(res), dynamicType(d) FROM test;
```

```text theme={null}
Received exception:
Code: 43. DB::Exception: Illegal types Array(Int64) and UInt8 of arguments of function plus: while executing 'FUNCTION plus(__table1.d : 3, 1_UInt8 :: 1) -> plus(__table1.d, 1_UInt8) Dynamic : 0'. (ILLEGAL_TYPE_OF_ARGUMENT)
```

On peut filtrer les types inutiles :

```sql theme={null}
SELECT d, d + 1 AS res, toTypeName(res), dynamicType(res) FROM test WHERE dynamicType(d) NOT IN ('String', 'Array(Int64)', 'None')
```

```text theme={null}
┌─d──┬─res─┬─toTypeName(res)─┬─dynamicType(res)─┐
│ 42 │ 43  │ Dynamic         │ Int64            │
│ 43 │ 44  │ Dynamic         │ Int64            │
└────┴─────┴─────────────────┴──────────────────┘
```

Ou extraire le type requis comme sous-colonne :

```sql theme={null}
SELECT d, d.Int64 + 1 AS res, toTypeName(res) FROM test;
```

```text theme={null}
┌─d─────┬──res─┬─toTypeName(res)─┐
│ 42    │   43 │ Nullable(Int64) │
│ 43    │   44 │ Nullable(Int64) │
│ str_1 │ ᴺᵁᴸᴸ │ Nullable(Int64) │
└───────┴──────┴─────────────────┘
┌─d─────┬──res─┬─toTypeName(res)─┐
│ ᴺᵁᴸᴸ  │ ᴺᵁᴸᴸ │ Nullable(Int64) │
│ [1,2] │ ᴺᵁᴸᴸ │ Nullable(Int64) │
│ [3,4] │ ᴺᵁᴸᴸ │ Nullable(Int64) │
└───────┴──────┴─────────────────┘
```

<div id="dynamic-type-mismatch-behavior">
  ### Comportement en cas d’incompatibilité de type
</div>

Le paramètre `dynamic_throw_on_type_mismatch` contrôle ce qui se produit lorsqu’une fonction est appliquée à une colonne `Dynamic` et que le type réellement stocké dans une ligne est incompatible avec cette fonction :

* `true` (par défaut) — lever une exception (`ILLEGAL_TYPE_OF_ARGUMENT`) dès la première ligne incompatible.
* `false` — renvoyer `NULL` pour les lignes incompatibles et conserver le résultat pour les lignes compatibles.

**Exemple :**

```sql theme={null}
CREATE TABLE test (d Dynamic) ENGINE = Memory;
INSERT INTO test VALUES ('world'), (123), (456);

-- Default (throw on mismatch): length() does not accept integers, so the query throws.
SELECT length(d) FROM test;  -- throws ILLEGAL_TYPE_OF_ARGUMENT

-- With throw disabled: incompatible rows return NULL.
SET dynamic_throw_on_type_mismatch = false;
SELECT d, length(d) FROM test ORDER BY d::String NULLS LAST;
```

```text theme={null}
┌─d─────┬─length(d)─┐
│ world │         5 │
│ 123   │      ᴺᵁᴸᴸ │
│ 456   │      ᴺᵁᴸᴸ │
└───────┴───────────┘
```

<div id="using-dynamic-type-in-order-by-and-group-by">
  ## Utilisation du type Dynamic dans ORDER BY et GROUP BY
</div>

Lors de `ORDER BY` et `GROUP BY`, les valeurs de type `Dynamic` sont comparées de manière similaire aux valeurs de type `Variant` :
Le résultat de l’opérateur `<` pour les valeurs `d1` de type sous-jacent `T1` et `d2` de type sous-jacent `T2` d’un type `Dynamic` est défini comme suit :

* Si `T1 = T2 = T`, le résultat sera `d1.T < d2.T` (les valeurs sous-jacentes seront comparées).
* Si `T1 != T2`, le résultat sera `T1 < T2` (les noms de type seront comparés).

Par défaut, le type `Dynamic` n’est pas autorisé dans les clés `GROUP BY`/`ORDER BY` ; si vous souhaitez l’utiliser, tenez compte de cette règle de comparaison particulière et activez les paramètres `allow_suspicious_types_in_group_by`/`allow_suspicious_types_in_order_by`.

Exemples :

```sql theme={null}
CREATE TABLE test (d Dynamic) ENGINE=Memory;
INSERT INTO test VALUES (42), (43), ('abc'), ('abd'), ([1, 2, 3]), ([]), (NULL);
```

```sql theme={null}
SELECT d, dynamicType(d) FROM test;
```

```text theme={null}
┌─d───────┬─dynamicType(d)─┐
│ 42      │ Int64          │
│ 43      │ Int64          │
│ abc     │ String         │
│ abd     │ String         │
│ [1,2,3] │ Array(Int64)   │
│ []      │ Array(Int64)   │
│ ᴺᵁᴸᴸ    │ None           │
└─────────┴────────────────┘
```

```sql theme={null}
SELECT d, dynamicType(d) FROM test ORDER BY d SETTINGS allow_suspicious_types_in_order_by=1;
```

```sql theme={null}
┌─d───────┬─dynamicType(d)─┐
│ []      │ Array(Int64)   │
│ [1,2,3] │ Array(Int64)   │
│ 42      │ Int64          │
│ 43      │ Int64          │
│ abc     │ String         │
│ abd     │ String         │
│ ᴺᵁᴸᴸ    │ None           │
└─────────┴────────────────┘
```

**Remarque :** les valeurs de type Dynamic dont les types numériques diffèrent sont considérées comme des valeurs distinctes et ne sont pas comparées entre elles ; ce sont leurs noms de type qui sont comparés à la place.

Exemple :

```sql theme={null}
CREATE TABLE test (d Dynamic) ENGINE=Memory;
INSERT INTO test VALUES (1::UInt32), (1::Int64), (100::UInt32), (100::Int64);
SELECT d, dynamicType(d) FROM test ORDER BY d SETTINGS allow_suspicious_types_in_order_by=1;
```

```text theme={null}
┌─v───┬─dynamicType(v)─┐
│ 1   │ Int64          │
│ 100 │ Int64          │
│ 1   │ UInt32         │
│ 100 │ UInt32         │
└─────┴────────────────┘
```

```sql theme={null}
SELECT d, dynamicType(d) FROM test GROUP BY d SETTINGS allow_suspicious_types_in_group_by=1;
```

```text theme={null}
┌─d───┬─dynamicType(d)─┐
│ 1   │ Int64          │
│ 100 │ UInt32         │
│ 1   │ UInt32         │
│ 100 │ Int64          │
└─────┴────────────────┘
```

**Remarque :** la règle de comparaison décrite ne s’applique pas lors de l’exécution des fonctions de comparaison telles que `<`/`>`/`=` et d’autres, en raison du [fonctionnement particulier](#using-dynamic-type-in-functions) des fonctions avec le type `Dynamic`

<div id="reaching-the-limit-in-number-of-different-data-types-stored-inside-dynamic">
  ## Atteinte de la limite du nombre de types de données différents stockés dans Dynamic
</div>

Le type de données `Dynamic` ne peut stocker qu'un nombre limité de types de données différents en tant que sous-colonnes distinctes. Par défaut, cette limite est de 32, mais vous pouvez la modifier dans la déclaration du type à l'aide de la syntaxe `Dynamic(max_types=N)`, où N est compris entre 0 et 254 (pour des raisons liées aux détails d’implémentation, il est impossible d'avoir plus de 254 types de données différents pouvant être stockés en tant que sous-colonnes distinctes dans Dynamic).
Lorsque cette limite est atteinte, tous les nouveaux types de données insérés dans la colonne `Dynamic` sont insérés dans une structure de données partagée unique, qui stocke des valeurs de types de données différents sous forme binaire.

Voyons ce qui se passe lorsque cette limite est atteinte dans différents scénarios.

<div id="reaching-the-limit-during-data-parsing">
  ### Limite atteinte lors de l’analyse des données
</div>

Lors de l’analyse des valeurs `Dynamic` à partir des données, lorsque la limite est atteinte pour le bloc de données actuel, toutes les nouvelles valeurs seront insérées dans la structure de données partagée :

```sql theme={null}
SELECT d, dynamicType(d), isDynamicElementInSharedData(d) FROM format(JSONEachRow, 'd Dynamic(max_types=3)', '
{"d" : 42}
{"d" : [1, 2, 3]}
{"d" : "Hello, World!"}
{"d" : "2020-01-01"}
{"d" : ["str1", "str2", "str3"]}
{"d" : {"a" : 1, "b" : [1, 2, 3]}}
')
```

```text theme={null}
┌─d──────────────────────┬─dynamicType(d)─────────────────┬─isDynamicElementInSharedData(d)─┐
│ 42                     │ Int64                          │ false                           │
│ [1,2,3]                │ Array(Int64)                   │ false                           │
│ Hello, World!          │ String                         │ false                           │
│ 2020-01-01             │ Date                           │ true                            │
│ ['str1','str2','str3'] │ Array(String)                  │ true                            │
│ (1,[1,2,3])            │ Tuple(a Int64, b Array(Int64)) │ true                            │
└────────────────────────┴────────────────────────────────┴─────────────────────────────────┘
```

Comme on peut le voir, après l’insertion de 3 types de données différents, `Int64`, `Array(Int64)` et `String`, tous ces nouveaux types ont été insérés dans une structure spéciale de données partagées.

<div id="during-merges-of-data-parts-in-mergetree-table-engines">
  ### Lors des fusions de parties de données dans les moteurs de table MergeTree
</div>

Lors de la fusion de plusieurs parties de données dans une table MergeTree, la colonne `Dynamic` de la partie de données résultante peut atteindre la limite du nombre de types de données différents pouvant être stockés dans des sous-colonnes distinctes, et ne plus pouvoir stocker tous les types sous forme de sous-colonnes provenant des parties source.
Dans ce cas, ClickHouse choisit quels types resteront dans des sous-colonnes distinctes après la fusion et quels types seront insérés dans la structure de données partagée. Dans la plupart des cas, ClickHouse essaie de conserver les types les plus fréquents et de stocker les types les plus rares dans la structure de données partagée, mais cela dépend de l’implémentation.

Voyons un exemple d’une telle fusion. Commençons par créer une table avec une colonne `Dynamic`, définissons la limite du nombre de types de données différents à `3` et insérons des valeurs de `5` types différents :

```sql theme={null}
CREATE TABLE test (id UInt64, d Dynamic(max_types=3)) ENGINE=MergeTree ORDER BY id;
SYSTEM STOP MERGES test;
INSERT INTO test SELECT number, number FROM numbers(5);
INSERT INTO test SELECT number, range(number) FROM numbers(4);
INSERT INTO test SELECT number, toDate(number) FROM numbers(3);
INSERT INTO test SELECT number, map(number, number) FROM numbers(2);
INSERT INTO test SELECT number, 'str_' || toString(number) FROM numbers(1);
```

Chaque insertion créera une partie de données distincte avec une colonne `Dynamic` ne contenant qu’un seul type :

```sql theme={null}
SELECT count(), dynamicType(d), isDynamicElementInSharedData(d), _part FROM test GROUP BY _part, dynamicType(d), isDynamicElementInSharedData(d) ORDER BY _part, count();
```

```text theme={null}
┌─count()─┬─dynamicType(d)──────┬─isDynamicElementInSharedData(d)─┬─_part─────┐
│       5 │ UInt64              │ false                           │ all_1_1_0 │
│       4 │ Array(UInt64)       │ false                           │ all_2_2_0 │
│       3 │ Date                │ false                           │ all_3_3_0 │
│       2 │ Map(UInt64, UInt64) │ false                           │ all_4_4_0 │
│       1 │ String              │ false                           │ all_5_5_0 │
└─────────┴─────────────────────┴─────────────────────────────────┴───────────┘
```

Maintenant, fusionnons toutes les parts en une seule et voyons ce qui se passe :

```sql theme={null}
SYSTEM START MERGES test;
OPTIMIZE TABLE test FINAL;
SELECT count(), dynamicType(d), isDynamicElementInSharedData(d), _part FROM test GROUP BY _part, dynamicType(d), isDynamicElementInSharedData(d) ORDER BY _part, count() desc;
```

```text theme={null}
┌─count()─┬─dynamicType(d)──────┬─isDynamicElementInSharedData(d)─┬─_part─────┐
│       5 │ UInt64              │ false                           │ all_1_5_2 │
│       4 │ Array(UInt64)       │ false                           │ all_1_5_2 │
│       3 │ Date                │ false                           │ all_1_5_2 │
│       2 │ Map(UInt64, UInt64) │ true                            │ all_1_5_2 │
│       1 │ String              │ true                            │ all_1_5_2 │
└─────────┴─────────────────────┴─────────────────────────────────┴───────────┘
```

Comme on peut le voir, ClickHouse a conservé les types les plus fréquents `UInt64` et `Array(UInt64)` sous forme de sous-colonnes, et a inséré tous les autres types dans les données partagées.

<div id="jsonextract-functions-with-dynamic">
  ## Fonctions JSONExtract avec Dynamic
</div>

Toutes les fonctions `JSONExtract*` prennent en charge le type `Dynamic` :

```sql theme={null}
SELECT JSONExtract('{"a" : [1, 2, 3]}', 'a', 'Dynamic') AS dynamic, dynamicType(dynamic) AS dynamic_type;
```

```text theme={null}
┌─dynamic─┬─dynamic_type───────────┐
│ [1,2,3] │ Array(Nullable(Int64)) │
└─────────┴────────────────────────┘
```

```sql theme={null}
SELECT JSONExtract('{"obj" : {"a" : 42, "b" : "Hello", "c" : [1,2,3]}}', 'obj', 'Map(String, Dynamic)') AS map_of_dynamics, mapApply((k, v) -> (k, dynamicType(v)), map_of_dynamics) AS map_of_dynamic_types
```

```text theme={null}
┌─map_of_dynamics──────────────────┬─map_of_dynamic_types────────────────────────────────────┐
│ {'a':42,'b':'Hello','c':[1,2,3]} │ {'a':'Int64','b':'String','c':'Array(Nullable(Int64))'} │
└──────────────────────────────────┴─────────────────────────────────────────────────────────┘
```

````sql theme={null}
SELECT JSONExtractKeysAndValues('{"a" : 42, "b" : "Hello", "c" : [1,2,3]}', 'Dynamic') AS dynamics, arrayMap(x -> (x.1, dynamicType(x.2)), dynamics) AS dynamic_types```
````

```text theme={null}
┌─dynamics───────────────────────────────┬─dynamic_types─────────────────────────────────────────────────┐
│ [('a',42),('b','Hello'),('c',[1,2,3])] │ [('a','Int64'),('b','String'),('c','Array(Nullable(Int64))')] │
└────────────────────────────────────────┴───────────────────────────────────────────────────────────────┘
```

<div id="binary-output-format">
  ### Format de sortie binaire
</div>

Au format RowBinary, les valeurs de type `Dynamic` sont sérialisées comme suit :

```text theme={null}
<binary_encoded_data_type><value_in_binary_format_according_to_the_data_type>
```
