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

> Documentação do tipo de dados Dynamic no ClickHouse, que pode armazenar valores de tipos diferentes em uma única coluna

# Dynamic

Esse tipo permite armazenar valores de qualquer tipo sem precisar conhecer todos eles antecipadamente.

Para declarar uma coluna do tipo `Dynamic`, use a seguinte sintaxe:

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

Onde `N` é um parâmetro opcional entre `0` e `254` que indica quantos tipos de dados diferentes podem ser armazenados como subcolunas separadas dentro de uma coluna do tipo `Dynamic` em um único bloco de dados armazenado separadamente (por exemplo, em uma única parte de dados de uma tabela MergeTree). Se esse limite for excedido, todos os valores com novos tipos serão armazenados juntos em uma estrutura de dados compartilhada especial em formato binário. O valor padrão de `max_types` é `32`.

<div id="creating-dynamic">
  ## Criando Dynamic
</div>

Usando o tipo `Dynamic` na definição de uma coluna da tabela:

```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)   │
└───────────────┴────────────────┘
```

Usando CAST em uma coluna comum:

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

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

Usando CAST na coluna `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">
  ## Lendo tipos aninhados de `Dynamic` como subcolunas
</div>

O tipo `Dynamic` oferece suporte à leitura de um único tipo aninhado de uma coluna `Dynamic` usando o nome do tipo como subcoluna.
Assim, se você tiver a coluna `d Dynamic`, poderá ler uma subcoluna de qualquer tipo válido `T` usando a sintaxe `d.T`.
Essa subcoluna terá o tipo `Nullable(T)` se `T` puder estar dentro de `Nullable`; caso contrário, terá o tipo `T`. Essa subcoluna
terá o mesmo tamanho da coluna `Dynamic` original e conterá valores `NULL` (ou valores vazios, se `T` não puder estar dentro de `Nullable`)
em todas as linhas em que a coluna `Dynamic` original não tiver o tipo `T`.

As subcolunas de `Dynamic` também podem ser lidas usando a função `dynamicElement(dynamic_column, type_name)`.

Exemplos:

```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]                           │                      ᴺᵁᴸᴸ │ []                                 │
└───────────────┴────────────────┴─────────────────────────────┴────────────────────────────┴───────────────────────────────────┴───────────────────────────┴────────────────────────────────────┘
```

Para saber qual variante está armazenada em cada linha, pode-se usar a função `dynamicType(dynamic_column)`. Ela retorna `String` contendo o nome do tipo do valor para cada linha (ou `'None'` se a linha for `NULL`).

Exemplo:

```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">
  ## Conversão entre a coluna Dynamic e outras colunas
</div>

Há 4 conversões possíveis que podem ser feitas com a coluna `Dynamic`.

<div id="converting-an-ordinary-column-to-a-dynamic-column">
  ### Convertendo uma coluna comum em uma coluna 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">
  ### Convertendo uma coluna String em uma coluna Dynamic por meio de parsing
</div>

Para fazer o parsing de valores do tipo `Dynamic` a partir de uma coluna `String`, você pode habilitar a configuração `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">
  ### Convertendo uma coluna Dynamic em uma coluna comum
</div>

É possível converter uma coluna `Dynamic` em uma coluna comum. Nesse caso, todos os tipos aninhados serão convertidos para um tipo de destino:

```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">
  ### Convertendo uma coluna Variant para uma coluna 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">
  ### Convertendo uma coluna Dynamic(max\_types=N) em outra Dynamic(max\_types=K)
</div>

Se `K >= N`, os dados não mudam durante a conversão:

```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           │
└───────┴────────────────┘
```

Se `K < N`, então os valores com os tipos mais raros serão inseridos em uma única subcoluna especial, mas ainda continuarão acessíveis:

```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                             │
└─────────┴────────────────┴─────────┴─────────────────┴──────────────────────────────────┘
```

A função `isDynamicElementInSharedData` retorna `true` para as linhas armazenadas em uma estrutura de dados compartilhada especial dentro de `Dynamic` e, como podemos ver, a coluna resultante contém apenas 2 tipos que não são armazenados nessa estrutura de dados compartilhada.

Se `K=0`, todos os tipos serão inseridos em uma única subcoluna especial:

```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">
  ## Lendo o tipo Dynamic a partir dos dados
</div>

Todos os formatos de texto (TSV, CSV, CustomSeparated, Values, JSONEachRow etc.) permitem ler o tipo `Dynamic`. Durante o parsing dos dados, o ClickHouse tenta inferir o tipo de cada valor e usá-lo durante a inserção em uma coluna `Dynamic`.

Exemplo:

```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">
  ## Usando o tipo Dynamic em funções
</div>

A maioria das funções aceita argumentos do tipo `Dynamic`. Nesse caso, a função é executada separadamente para cada tipo de dado interno armazenado na coluna `Dynamic`.
Quando o tipo de resultado da função depende dos tipos dos argumentos, o resultado de tal função executada com argumentos `Dynamic` será `Dynamic`. Quando o tipo de resultado da função não depende dos tipos dos argumentos, o resultado será `Nullable(T)`, onde `T` é o tipo de resultado usual dessa função.

Exemplos:

```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            │
└───────┴──────┴─────────────────┴──────────────────┘
```

Se a função não puder ser executada em algum tipo na coluna `Dynamic`, uma exceção será lançada:

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

Podemos filtrar os tipos desnecessários:

```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 extraia o tipo necessário como subcoluna:

```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">
  ### Comportamento em caso de incompatibilidade de tipo
</div>

A configuração `dynamic_throw_on_type_mismatch` controla o que acontece quando uma função é aplicada a uma coluna `Dynamic` e o tipo realmente armazenado em uma linha é incompatível com a função:

* `true` (padrão) — lança uma exceção (`ILLEGAL_TYPE_OF_ARGUMENT`) na primeira linha incompatível.
* `false` — retorna `NULL` para as linhas incompatíveis e mantém o resultado para as linhas compatíveis.

**Exemplo:**

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

-- Padrão (lançar exceção em caso de incompatibilidade): length() não aceita inteiros, então a consulta lança uma exceção.
SELECT length(d) FROM test;  -- lança ILLEGAL_TYPE_OF_ARGUMENT

-- Com o lançamento de exceção desativado: linhas incompatíveis retornam 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">
  ## Usando o tipo Dynamic em ORDER BY e GROUP BY
</div>

Em `ORDER BY` e `GROUP BY`, os valores do tipo `Dynamic` são comparados de forma semelhante aos valores do tipo `Variant`:
O resultado do operador `<` para os valores `d1`, com tipo subjacente `T1`, e `d2`, com tipo subjacente `T2`, de um tipo `Dynamic` é definido da seguinte forma:

* Se `T1 = T2 = T`, o resultado será `d1.T < d2.T` (os valores subjacentes serão comparados).
* Se `T1 != T2`, o resultado será `T1 < T2` (os nomes dos tipos serão comparados).

Por padrão, o tipo `Dynamic` não é permitido em chaves de `GROUP BY`/`ORDER BY`. Se quiser usá-lo, leve em consideração sua regra especial de comparação e habilite as configurações `allow_suspicious_types_in_group_by`/`allow_suspicious_types_in_order_by`.

Exemplos:

```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           │
└─────────┴────────────────┘
```

**Observação:** valores de tipos Dynamic com tipos numéricos diferentes são considerados distintos e não são comparados entre si; em vez disso, seus nomes de tipo são comparados.

Exemplo:

```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          │
└─────┴────────────────┘
```

**Observação:** a regra de comparação descrita não é aplicada durante a execução de funções de comparação como `<`/`>`/`=` e outras, devido ao [comportamento especial](#using-dynamic-type-in-functions) das funções com o tipo `Dynamic`

<div id="reaching-the-limit-in-number-of-different-data-types-stored-inside-dynamic">
  ## Atingindo o limite do número de diferentes tipos de dados armazenados em Dynamic
</div>

O tipo de dado `Dynamic` pode armazenar apenas um número limitado de diferentes tipos de dados como subcolunas separadas. Por padrão, esse limite é 32, mas você pode alterá-lo na declaração do tipo usando a sintaxe `Dynamic(max_types=N)`, em que N fica entre 0 e 254 (devido a detalhes de implementação, é impossível ter mais de 254 tipos de dados diferentes que possam ser armazenados como subcolunas separadas em Dynamic).
Quando esse limite é atingido, todos os novos tipos de dados inseridos na coluna `Dynamic` passam a ser inseridos em uma única estrutura de dados compartilhada, que armazena valores com diferentes tipos de dados em formato binário.

Vamos ver o que acontece quando esse limite é atingido em diferentes cenários.

<div id="reaching-the-limit-during-data-parsing">
  ### Atingindo o limite durante o parsing dos dados
</div>

Durante o parsing de valores `Dynamic` a partir dos dados, quando o limite é atingido no bloco de dados atual, todos os novos valores serão inseridos na estrutura de dados compartilhada:

```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                            │
└────────────────────────┴────────────────────────────────┴─────────────────────────────────┘
```

Como podemos ver, após a inserção de 3 tipos de dados diferentes — `Int64`, `Array(Int64)` e `String` —, todos os novos tipos foram inseridos em uma estrutura de dados compartilhada especial.

<div id="during-merges-of-data-parts-in-mergetree-table-engines">
  ### Durante mesclagens de partes de dados em motores de tabela MergeTree
</div>

Durante a mesclagem de várias partes de dados em uma tabela MergeTree, a coluna `Dynamic` na parte de dados resultante pode atingir o limite de diferentes tipos de dados que podem ser armazenados em subcolunas separadas e não conseguir armazenar todos os tipos como subcolunas das partes de origem.
Nesse caso, o ClickHouse escolhe quais tipos permanecerão como subcolunas separadas após a mesclagem e quais tipos serão inseridos na estrutura de dados compartilhada. Na maioria dos casos, o ClickHouse tenta manter os tipos mais frequentes e armazenar os mais raros na estrutura de dados compartilhada, mas isso depende da implementação.

Vamos ver um exemplo desse tipo de mesclagem. Primeiro, vamos criar uma tabela com uma coluna `Dynamic`, definir o limite de diferentes tipos de dados como `3` e inserir valores com `5` tipos diferentes:

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

Cada inserção criará uma parte de dados separada, com a coluna `Dynamic` contendo um único tipo:

```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 │
└─────────┴─────────────────────┴─────────────────────────────────┴───────────┘
```

Agora, vamos unir todas as partes em uma só e ver o que acontece:

```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 │
└─────────┴─────────────────────┴─────────────────────────────────┴───────────┘
```

Como podemos ver, o ClickHouse manteve os tipos mais frequentes `UInt64` e `Array(UInt64)` como subcolunas e inseriu todos os demais tipos nos dados compartilhados.

<div id="jsonextract-functions-with-dynamic">
  ## Funções JSONExtract com Dynamic
</div>

Todas as funções `JSONExtract*` são compatíveis com o tipo `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">
  ### Formato de saída binária
</div>

No formato RowBinary, os valores do tipo `Dynamic` são serializados no formato a seguir:

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