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

# types de disposition du dictionnaire range_hashed

> Stocker un dictionnaire en mémoire à l’aide d’une table de hachage avec des intervalles date/heure ordonnés.

<div id="range_hashed">
  ## range\_hashed
</div>

Le dictionnaire est stocké en mémoire sous la forme d'une table de hachage avec un tableau ordonné de plages et de leurs valeurs correspondantes.

Cette méthode de stockage fonctionne comme hashed et permet d'utiliser, en plus de la clé, des plages de dates/heures (de type numérique arbitraire).

Exemple : la table contient des remises pour chaque annonceur, au format :

```text theme={null}
┌─advertiser_id─┬─discount_start_date─┬─discount_end_date─┬─amount─┐
│           123 │          2015-01-16 │        2015-01-31 │   0.25 │
│           123 │          2015-01-01 │        2015-01-15 │   0.15 │
│           456 │          2015-01-01 │        2015-01-15 │   0.05 │
└───────────────┴─────────────────────┴───────────────────┴────────┘
```

Pour utiliser un échantillon avec des plages de dates, définissez les éléments `range_min` et `range_max` dans la [structure](/fr/reference/statements/create/dictionary/attributes#composite-key). Ces éléments doivent inclure les éléments `name` et `type` (si `type` n'est pas spécifié, le type par défaut sera utilisé : Date). `type` peut être n'importe quel type numérique (Date / DateTime / UInt64 / Int32 / autres).

<Note>
  Les valeurs de `range_min` et `range_max` doivent pouvoir être représentées par le type `Int64`.
</Note>

Exemple :

<Tabs>
  <Tab title="DDL">
    ```sql theme={null}
    CREATE DICTIONARY discounts_dict (
        advertiser_id UInt64,
        discount_start_date Date,
        discount_end_date Date,
        amount Float64
    )
    PRIMARY KEY id
    SOURCE(CLICKHOUSE(TABLE 'discounts'))
    LIFETIME(MIN 1 MAX 1000)
    LAYOUT(RANGE_HASHED(range_lookup_strategy 'max'))
    RANGE(MIN discount_start_date MAX discount_end_date)
    ```
  </Tab>

  <Tab title="Fichier de configuration">
    ```xml theme={null}
    <layout>
        <range_hashed>
            <!-- Stratégie pour les plages qui se chevauchent (min/max). Par défaut : min (renvoie une plage correspondante avec la valeur min(range_min -> range_max)) -->
            <range_lookup_strategy>min</range_lookup_strategy>
        </range_hashed>
    </layout>
    <structure>
        <id>
            <name>advertiser_id</name>
        </id>
        <range_min>
            <name>discount_start_date</name>
            <type>Date</type>
        </range_min>
        <range_max>
            <name>discount_end_date</name>
            <type>Date</type>
        </range_max>
        ...
    ```
  </Tab>
</Tabs>

<br />

Pour utiliser ces dictionnaires, vous devez passer un argument supplémentaire à la fonction `dictGet`, auquel une plage est appliquée :

```sql theme={null}
dictGet('dict_name', 'attr_name', id, date)
```

Exemple de requête :

```sql theme={null}
SELECT dictGet('discounts_dict', 'amount', 1, '2022-10-20'::Date);
```

Cette fonction renvoie la valeur pour les `id` spécifiés et la plage de dates qui inclut la date fournie.

Détails de l’algorithme :

* Si l’`id` est introuvable ou si aucune plage n’est trouvée pour cet `id`, elle renvoie la valeur par défaut du type de l’attribut.
* S’il existe des plages qui se chevauchent et que `range_lookup_strategy=min`, elle renvoie une plage correspondante dont le `range_min` est minimal ; si plusieurs plages sont trouvées, elle renvoie une plage dont le `range_max` est minimal ; si plusieurs plages sont encore trouvées (plusieurs plages ayant le même `range_min` et le même `range_max`), elle renvoie l’une d’elles aléatoirement.
* S’il existe des plages qui se chevauchent et que `range_lookup_strategy=max`, elle renvoie une plage correspondante dont le `range_min` est maximal ; si plusieurs plages sont trouvées, elle renvoie une plage dont le `range_max` est maximal ; si plusieurs plages sont encore trouvées (plusieurs plages ayant le même `range_min` et le même `range_max`), elle renvoie l’une d’elles aléatoirement.
* Si `range_max` vaut `NULL`, la plage est ouverte. `NULL` est traité comme la valeur maximale possible. Pour `range_min`, `1970-01-01` ou `0` (-MAX\_INT) peuvent être utilisés comme valeur ouverte.

Exemple de configuration :

<Tabs>
  <Tab title="DDL">
    ```sql theme={null}
    CREATE DICTIONARY somedict(
        Abcdef UInt64,
        StartTimeStamp UInt64,
        EndTimeStamp UInt64,
        XXXType String DEFAULT ''
    )
    PRIMARY KEY Abcdef
    RANGE(MIN StartTimeStamp MAX EndTimeStamp)
    ```
  </Tab>

  <Tab title="Fichier de configuration">
    ```xml theme={null}
    <clickhouse>
        <dictionary>
            ...

            <layout>
                <range_hashed />
            </layout>

            <structure>
                <id>
                    <name>Abcdef</name>
                </id>
                <range_min>
                    <name>StartTimeStamp</name>
                    <type>UInt64</type>
                </range_min>
                <range_max>
                    <name>EndTimeStamp</name>
                    <type>UInt64</type>
                </range_max>
                <attribute>
                    <name>XXXType</name>
                    <type>String</type>
                    <null_value />
                </attribute>
            </structure>

        </dictionary>
    </clickhouse>
    ```
  </Tab>
</Tabs>

<br />

Exemple de configuration avec des plages qui se chevauchent et des plages ouvertes :

```sql theme={null}
CREATE TABLE discounts
(
    advertiser_id UInt64,
    discount_start_date Date,
    discount_end_date Nullable(Date),
    amount Float64
)
ENGINE = Memory;

INSERT INTO discounts VALUES (1, '2015-01-01', Null, 0.1);
INSERT INTO discounts VALUES (1, '2015-01-15', Null, 0.2);
INSERT INTO discounts VALUES (2, '2015-01-01', '2015-01-15', 0.3);
INSERT INTO discounts VALUES (2, '2015-01-04', '2015-01-10', 0.4);
INSERT INTO discounts VALUES (3, '1970-01-01', '2015-01-15', 0.5);
INSERT INTO discounts VALUES (3, '1970-01-01', '2015-01-10', 0.6);

SELECT * FROM discounts ORDER BY advertiser_id, discount_start_date;
┌─advertiser_id─┬─discount_start_date─┬─discount_end_date─┬─amount─┐
│             1 │          2015-01-01 │              ᴺᵁᴸᴸ │    0.1 │
│             1 │          2015-01-15 │              ᴺᵁᴸᴸ │    0.2 │
│             2 │          2015-01-01 │        2015-01-15 │    0.3 │
│             2 │          2015-01-04 │        2015-01-10 │    0.4 │
│             3 │          1970-01-01 │        2015-01-15 │    0.5 │
│             3 │          1970-01-01 │        2015-01-10 │    0.6 │
└───────────────┴─────────────────────┴───────────────────┴────────┘

-- RANGE_LOOKUP_STRATEGY 'max'

CREATE DICTIONARY discounts_dict
(
    advertiser_id UInt64,
    discount_start_date Date,
    discount_end_date Nullable(Date),
    amount Float64
)
PRIMARY KEY advertiser_id
SOURCE(CLICKHOUSE(TABLE discounts))
LIFETIME(MIN 600 MAX 900)
LAYOUT(RANGE_HASHED(RANGE_LOOKUP_STRATEGY 'max'))
RANGE(MIN discount_start_date MAX discount_end_date);

select dictGet('discounts_dict', 'amount', 1, toDate('2015-01-14')) res;
┌─res─┐
│ 0.1 │ -- the only one range is matching: 2015-01-01 - Null
└─────┘

select dictGet('discounts_dict', 'amount', 1, toDate('2015-01-16')) res;
┌─res─┐
│ 0.2 │ -- two ranges are matching, range_min 2015-01-15 (0.2) is bigger than 2015-01-01 (0.1)
└─────┘

select dictGet('discounts_dict', 'amount', 2, toDate('2015-01-06')) res;
┌─res─┐
│ 0.4 │ -- two ranges are matching, range_min 2015-01-04 (0.4) is bigger than 2015-01-01 (0.3)
└─────┘

select dictGet('discounts_dict', 'amount', 3, toDate('2015-01-01')) res;
┌─res─┐
│ 0.5 │ -- two ranges are matching, range_min are equal, 2015-01-15 (0.5) is bigger than 2015-01-10 (0.6)
└─────┘

DROP DICTIONARY discounts_dict;

-- RANGE_LOOKUP_STRATEGY 'min'

CREATE DICTIONARY discounts_dict
(
    advertiser_id UInt64,
    discount_start_date Date,
    discount_end_date Nullable(Date),
    amount Float64
)
PRIMARY KEY advertiser_id
SOURCE(CLICKHOUSE(TABLE discounts))
LIFETIME(MIN 600 MAX 900)
LAYOUT(RANGE_HASHED(RANGE_LOOKUP_STRATEGY 'min'))
RANGE(MIN discount_start_date MAX discount_end_date);

select dictGet('discounts_dict', 'amount', 1, toDate('2015-01-14')) res;
┌─res─┐
│ 0.1 │ -- the only one range is matching: 2015-01-01 - Null
└─────┘

select dictGet('discounts_dict', 'amount', 1, toDate('2015-01-16')) res;
┌─res─┐
│ 0.1 │ -- two ranges are matching, range_min 2015-01-01 (0.1) is less than 2015-01-15 (0.2)
└─────┘

select dictGet('discounts_dict', 'amount', 2, toDate('2015-01-06')) res;
┌─res─┐
│ 0.3 │ -- two ranges are matching, range_min 2015-01-01 (0.3) is less than 2015-01-04 (0.4)
└─────┘

select dictGet('discounts_dict', 'amount', 3, toDate('2015-01-01')) res;
┌─res─┐
│ 0.6 │ -- two ranges are matching, range_min are equal, 2015-01-10 (0.6) is less than 2015-01-15 (0.5)
└─────┘
```

<div id="complex_key_range_hashed">
  ## complex\_key\_range\_hashed
</div>

Le dictionnaire est stocké en mémoire sous la forme d’une table de hachage avec un tableau ordonné de plages et de leurs valeurs correspondantes (voir [range\_hashed](#range_hashed)). Ce type de stockage s’utilise avec des [clés](/fr/reference/statements/create/dictionary/attributes#composite-key) composites.

Exemple de configuration :

```sql theme={null}
CREATE DICTIONARY range_dictionary
(
  CountryID UInt64,
  CountryKey String,
  StartDate Date,
  EndDate Date,
  Tax Float64 DEFAULT 0.2
)
PRIMARY KEY CountryID, CountryKey
SOURCE(CLICKHOUSE(TABLE 'date_table'))
LIFETIME(MIN 1 MAX 1000)
LAYOUT(COMPLEX_KEY_RANGE_HASHED())
RANGE(MIN StartDate MAX EndDate);
```
