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

> Vue d’ensemble des structures de données imbriquées dans ClickHouse

# Nested(name1 Type1, Name2 Type2, ...)

Une structure de données imbriquée s’apparente à une table à l’intérieur d’une cellule. Les paramètres d’une structure de données imbriquée — les noms et les types des colonnes — sont spécifiés de la même manière que dans une requête [CREATE TABLE](/fr/reference/statements/create/table). Chaque ligne de table peut correspondre à un nombre quelconque de lignes dans une structure de données imbriquée.

<Tip>
  **Évitez d’utiliser des points dans les noms de colonnes**

  Les noms de colonnes contenant des points, les colonnes partageant un préfixe commun se terminant par un point, ainsi que les colonnes de type `Array`, peuvent chacun être interprétés comme faisant partie d’une structure `Nested` aplatie lorsque `flatten_nested = 1` (valeur par défaut). Cela peut entraîner une validation inattendue de la longueur des tableaux lors des insertions, ainsi que des restrictions de renommage.

  Évitez, si possible, d’utiliser des points dans les noms de colonnes.
  Utilisez des traits de soulignement (`_`) ou un autre séparateur à la place des points dans les noms de colonnes, sauf si vous avez volontairement besoin de la sémantique `Nested`.
</Tip>

Exemple :

```sql highlight={8-15} theme={null}
CREATE TABLE test.visits(
  CounterID UInt32,
  StartDate Date,
  Sign Int8,
  IsNew UInt8,
  VisitID UInt64,
  UserID UInt64,
  Goals Nested(
    ID UInt32,
    Serial UInt32,
    EventTime DateTime,
    Price Int64,
    OrderID String,
    CurrencyID UInt32
  )
)
ENGINE = CollapsingMergeTree(Sign)
ORDER BY (StartDate, intHash32(UserID), (CounterID, StartDate, intHash32(UserID), VisitID));

INSERT INTO test.visits
(CounterID, StartDate, Sign, IsNew, VisitID, UserID, Goals.ID, Goals.Serial, Goals.EventTime, Goals.Price, Goals.OrderID, Goals.CurrencyID)
VALUES
    (101500, '2014-03-17', 1, 1, 1001, 100001, [1073752, 591325, 591325], [1, 2, 3], ['2014-03-17 16:38:10', '2014-03-17 16:38:48', '2014-03-17 16:42:27'], [0, 0, 0], ['', '', ''], [0, 0, 0]),
    (101500, '2014-03-17', 1, 0, 1002, 100002, [1073752], [1], ['2014-03-17 00:28:25'], [0], [''], [0]),
    (101500, '2014-03-17', 1, 0, 1003, 100003, [1073752], [1], ['2014-03-17 10:46:20'], [0], [''], [0]),
    (101500, '2014-03-17', 1, 1, 1004, 100004, [1073752, 591325, 591325, 591325], [1, 2, 3, 4], ['2014-03-17 13:59:20', '2014-03-17 22:17:55', '2014-03-17 22:18:07', '2014-03-17 22:18:51'], [0, 0, 0, 0], ['', '', '', ''], [0, 0, 0, 0]),
    (101500, '2014-03-17', 1, 0, 1005, 100005, [], [], [], [], [], []),
    (101500, '2014-03-17', 1, 0, 1006, 100006, [1073752, 591325, 591325], [1, 2, 3], ['2014-03-17 11:37:06', '2014-03-17 14:07:47', '2014-03-17 14:36:21'], [0, 0, 0], ['', '', ''], [0, 0, 0]),
    (101500, '2014-03-17', 1, 0, 1007, 100007, [], [], [], [], [], []),
    (101500, '2014-03-17', 1, 0, 1008, 100008, [], [], [], [], [], []),
    (101500, '2014-03-17', 1, 1, 1009, 100009, [591325, 1073752], [1, 2], ['2014-03-17 00:46:05', '2014-03-17 00:46:05'], [0, 0], ['', ''], [0, 0]),
    (101500, '2014-03-17', 1, 1, 1010, 100010, [1073752, 591325, 591325, 591325], [1, 2, 3, 4], ['2014-03-17 13:28:33', '2014-03-17 13:30:26', '2014-03-17 18:51:21', '2014-03-17 18:51:45'], [0, 0, 0, 0], ['', '', '', ''], [0, 0, 0, 0]);
```

L’instruction DDL `CREATE TABLE` ci-dessus déclare la structure de données imbriquée `Goals`, qui contient des données sur les conversions, c’est-à-dire les objectifs atteints.
Chaque ligne de la table 'visits' correspond à zéro conversion ou plus.

Lorsque le paramètre [`flatten_nested`](/fr/reference/settings/session-settings#flatten_nested) est défini sur `0` (`flatten_nested=1` par défaut), des niveaux d’imbrication arbitraires sont pris en charge.

Dans la plupart des cas, lorsque vous travaillez avec une structure de données imbriquée, ses colonnes sont désignées par des noms de colonne séparés par un point.
Ces colonnes forment un tableau de types correspondants.
Tous les tableaux de colonnes d’une même structure de données imbriquée ont la même longueur.

Par exemple :

```sql theme={null}
SELECT
    Goals.ID,
    Goals.EventTime
FROM test.visits
WHERE CounterID = 101500 AND length(Goals.ID) < 5
ORDER BY VisitID
LIMIT 10
```

```text theme={null}
    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
    ┃ Goals.ID                       ┃ Goals.EventTime                                                                           ┃
    ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
 1. │ [1073752,591325,591325]        │ ['2014-03-17 16:38:10','2014-03-17 16:38:48','2014-03-17 16:42:27']                       │
    ├────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────┤
 2. │ [1073752]                      │ ['2014-03-17 00:28:25']                                                                   │
    ├────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────┤
 3. │ [1073752]                      │ ['2014-03-17 10:46:20']                                                                   │
    ├────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────┤
 4. │ [1073752,591325,591325,591325] │ ['2014-03-17 13:59:20','2014-03-17 22:17:55','2014-03-17 22:18:07','2014-03-17 22:18:51'] │
    ├────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────┤
 5. │ []                             │ []                                                                                        │
    ├────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────┤
 6. │ [1073752,591325,591325]        │ ['2014-03-17 11:37:06','2014-03-17 14:07:47','2014-03-17 14:36:21']                       │
    ├────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────┤
 7. │ []                             │ []                                                                                        │
    ├────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────┤
 8. │ []                             │ []                                                                                        │
    ├────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────┤
 9. │ [591325,1073752]               │ ['2014-03-17 00:46:05','2014-03-17 00:46:05']                                             │
    ├────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────┤
10. │ [1073752,591325,591325,591325] │ ['2014-03-17 13:28:33','2014-03-17 13:30:26','2014-03-17 18:51:21','2014-03-17 18:51:45'] │
    └────────────────────────────────┴───────────────────────────────────────────────────────────────────────────────────────────┘
```

<Tip>
  Il est plus simple de considérer une structure de données imbriquée comme un ensemble de plusieurs tableaux de colonnes de même longueur.
</Tip>

<div id="filtering-nested-columns-in-where">
  ### Filtrage des colonnes `Nested` dans `WHERE`
</div>

Comme chaque colonne d’une structure `Nested` est stockée sous forme d’`Array`, le fait d’y faire référence dans une clause `WHERE` renvoie l’intégralité du tableau pour chaque ligne, et non un élément individuel. Vous ne pouvez pas comparer directement une colonne `Nested` à une valeur scalaire ; vous devez donc utiliser des [array functions](/fr/reference/functions/regular-functions/array-functions).

Par exemple, cette requête ne se contente **pas** de ne renvoyer aucune ligne de façon silencieuse : elle déclenche une exception, car `Goals.ID` a pour type `Array(UInt32)` et `equals(Array(UInt32), UInt32)` n’est pas une comparaison valide :

```sql theme={null}
-- WRONG: compares the entire Array to a scalar
SELECT * FROM test.visits
WHERE Goals.ID = 591325;
```

```text theme={null}
Code: 43. DB::Exception: Illegal types of arguments (`Array(UInt32)`, `UInt32`)
of function `equals`. (ILLEGAL_TYPE_OF_ARGUMENT)
```

Utilisez [`has`](/fr/reference/functions/regular-functions/array-functions#has) pour vérifier si un tableau contient une valeur donnée :

```sql theme={null}
-- Find visits that have at least one goal with ID 591325
SELECT CounterID, VisitID, Goals.ID
FROM test.visits
WHERE has(Goals.ID, 591325);
```

Utilisez [`arrayExists`](/fr/reference/functions/regular-functions/array-functions#arrayExists) si la condition est plus complexe :

```sql theme={null}
-- Find visits that have at least one goal with ID greater than 1000000
SELECT CounterID, VisitID, Goals.ID
FROM test.visits
WHERE arrayExists(id -> id > 1000000, Goals.ID);
```

Vous pouvez filtrer selon la longueur des tableaux avec `length` ou exclure les tableaux vides avec `notEmpty` :

```sql theme={null}
-- Visits with at least 3 goals
SELECT CounterID, VisitID, Goals.ID
FROM test.visits
WHERE length(Goals.ID) >= 3;

-- Visits with at least one goal (non-empty array)
SELECT CounterID, VisitID, Goals.ID
FROM test.visits
WHERE notEmpty(Goals.ID);
```

Pour filtrer des éléments individuels d'une structure imbriquée plutôt que des lignes entières, utilisez `ARRAY JOIN` pour déployer d'abord les tableaux.
Après `ARRAY JOIN`, chaque élément devient une ligne distincte ; la clause `WHERE` s'applique donc à des valeurs scalaires.
Pour plus d'informations, consultez la [clause `ARRAY JOIN`](/fr/reference/statements/select/array-join). Exemple :

```sql theme={null}
SELECT
    Goal.ID,
    Goal.EventTime
FROM test.visits
ARRAY JOIN Goals AS Goal
WHERE CounterID = 101500 AND length(Goals.ID) < 5
ORDER BY VisitID, Goal.Serial
LIMIT 10
```

```text theme={null}
    ┏━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┓
    ┃ Goal.ID ┃      Goal.EventTime ┃
    ┡━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━┩
 1. │ 1073752 │ 2014-03-17 16:38:10 │
    ├─────────┼─────────────────────┤
 2. │  591325 │ 2014-03-17 16:38:48 │
    ├─────────┼─────────────────────┤
 3. │  591325 │ 2014-03-17 16:42:27 │
    ├─────────┼─────────────────────┤
 4. │ 1073752 │ 2014-03-17 00:28:25 │
    ├─────────┼─────────────────────┤
 5. │ 1073752 │ 2014-03-17 10:46:20 │
    ├─────────┼─────────────────────┤
 6. │ 1073752 │ 2014-03-17 13:59:20 │
    ├─────────┼─────────────────────┤
 7. │  591325 │ 2014-03-17 22:17:55 │
    ├─────────┼─────────────────────┤
 8. │  591325 │ 2014-03-17 22:18:07 │
    ├─────────┼─────────────────────┤
 9. │  591325 │ 2014-03-17 22:18:51 │
    ├─────────┼─────────────────────┤
10. │ 1073752 │ 2014-03-17 11:37:06 │
    └─────────┴─────────────────────┘
```

Vous ne pouvez pas exécuter `SELECT` sur l’ensemble d’une structure de données imbriquée. Vous pouvez seulement énumérer explicitement les colonnes individuelles qui la composent.

<div id="inserting-data">
  ### Insertion de données
</div>

Pour une requête `INSERT`, vous devez transmettre séparément tous les tableaux des colonnes composantes d'une structure de données imbriquée (comme s'il s'agissait de tableaux de colonnes distincts). Lors de l'insertion, le système vérifie qu'ils ont tous la même longueur.

Chaque sous-colonne imbriquée est indiquée dans la liste des colonnes à l'aide de la notation par points (`Goals.ID`, `Goals.Serial`, ...), et les valeurs correspondantes sont des tableaux :

```sql theme={null}
INSERT INTO test.visits
    (CounterID, StartDate, Sign, IsNew, VisitID, UserID,
     Goals.ID, Goals.Serial, Goals.EventTime, Goals.Price, Goals.OrderID, Goals.CurrencyID)
VALUES
    -- A visit with two goals: each nested sub-column gets an array of length 2
    (101500, '2014-03-18', 1, 1, 2001, 200001,
     [1073752, 591325], [1, 2],
     ['2014-03-18 10:00:00', '2014-03-18 10:05:00'],
     [100, 200], ['order_a', 'order_b'], [1, 2]),
    -- A visit with no goals: all nested sub-columns get empty arrays
    (101500, '2014-03-18', 1, 0, 2002, 200002,
     [], [], [], [], [], []);
```

Tous les tableaux de sous-colonnes imbriquées au sein d'une même ligne doivent avoir la même longueur. Des longueurs différentes provoquent une erreur :

```sql theme={null}
-- ERROR: Goals.ID has 2 elements, but Goals.Serial has 1
INSERT INTO test.visits
    (CounterID, StartDate, Sign, IsNew, VisitID, UserID,
     Goals.ID, Goals.Serial, Goals.EventTime, Goals.Price, Goals.OrderID, Goals.CurrencyID)
VALUES
    (101500, '2014-03-18', 1, 1, 2003, 200003,
     [1073752, 591325], [1],
     ['2014-03-18 12:00:00'], [0], [''], [0]);
```

Pour une requête `DESCRIBE`, les colonnes d'une structure de données imbriquée sont répertoriées séparément de la même façon.

<div id="alter-limitations">
  ### Limites d’ALTER
</div>

Les requêtes `ALTER` sur les structures de données imbriquées présentent les limites suivantes :

**L’ajout de sous-colonnes** fonctionne normalement. Vous pouvez ajouter une nouvelle sous-colonne à une structure `Nested` existante :

```sql theme={null}
ALTER TABLE test.visits ADD COLUMN Goals.Revenue Float64;
```

**La suppression des sous-colonnes** fonctionne pour chaque sous-colonne individuellement :

```sql theme={null}
ALTER TABLE test.visits DROP COLUMN Goals.Revenue;
```

**La modification du type** d’une sous-colonne fonctionne et déclenche une mutation (réécriture des données) :

```sql theme={null}
ALTER TABLE test.visits MODIFY COLUMN Goals.Price Int32;
```

Le **renommage** est soumis à certaines restrictions. Vous pouvez renommer une sous-colonne au sein de la même structure imbriquée :

```sql theme={null}
-- OK: stays within the Goals structure
ALTER TABLE test.visits RENAME COLUMN Goals.Price TO Goals.Amount;
```

Cependant, vous **ne pouvez pas** :

* Renommer la structure imbriquée entière (par exemple, `Goals` en `Conversions`).
* Déplacer une sous-colonne vers une autre structure imbriquée (par exemple, `Goals.ID` vers `OtherNested.ID`).
* Déplacer une sous-colonne hors d'une structure imbriquée ou l'y déplacer (par exemple, `Goals.ID` vers `GoalID`, ou inversement).
