# Tipos de conjunto y de rango

MobilityDB proporciona los tipos de conjunto, rango y conjunto de rangos para representar conjuntos de valores de otro tipo, que se denomina tipo base. Los tipos de conjunto son similares a los tipos de matrices de PostgreSQL restringidos a una dimensión, pero imponen la restricción de que los conjuntos no tienen duplicados. Los tipos de rango y conjunto de rangos en MobilityDB corresponden a los tipos de rango y multirango en PostgreSQL pero tienen restricciones adicionales. En particular, los tipos de rango en MobilityDB tienen una longitud fija y no permiten rangos vacíos ni límites infinitos. Si bien los tipos de rango en MobilityDB proporcionan una funcionalidad similar a los tipos de rango en PostgreSQL, los tipos de rango en MobilityDB permiten aumentar el rendimiento. En particular, se elimina la sobrecarga del procesamiento de tipos de longitud variable y, además, se pueden utilizar la aritmética de punteros y la búsqueda binaria.

Los tipos de base que se utilizan para construir tipos de conjunto, de rango y de conjunto de rangos son los tipos `integer`, `bigint`, `float`, `text`, `date`, and `timestamptz` (marca de tiempo con zona horaria) proporcionados por PostgreSQL, los tipos `geometry` y `geography` proporcionados por PostGIS, y el tipo `npoint` (network point o punto de red) proporcionado por MobilityDB (ver temporal_network_points). MobilityDB proporciona los siguientes tipos de conjunto y de rango:

- `set`: `intset`, `bigintset`, `floatset`, `textset`, `dateset`, `tstzset`, `geomset`, `geogset`, `npointset`.

- `span`: `intspan`, `bigintspan`, `floatspan`, `datespan`, `tstzspan`.

- `spanset`: `intspanset`, `bigintspanset`, `floatspanset`, `datespanset`, `tstzspanset`.

A continuación presentamos las funciones y operadores para tipos de conjunto y de rango. Estas funciones y operadores son polimórficos, es decir, sus argumentos pueden ser de varios tipos y el tipo de resultado puede depender del tipo de los argumentos. Para expresar esto en la firma de las funciones y los operadores, utilizamos la siguiente notación:

- `set` representa cualquier tipo de conjunto, como `intset` o `tstzset`.

- `span` representa cualquier tipo de rango, como `intspan` o `tstzspan`.

- `spanset` representa cualquier tipo de conjunto de rangos, como `intspanset` o `tstzspanset`.

- `spans` representa cualquier tipo de rango o conjunto de rangos, como `intspan` o `tstzspanset`.

- `base` representa cualquier tipo de base de un tipo de conjunto o de rango, como `integer` o `timestamptz`.

- `number` representa cualquier tipo de base de un tipo de rango numérico, como `integer` o `float`,

- `numset` representa cualquier tipo de conjunto numérico, como `intset` o `floatset`.

- `numspans` representa cualquier tipo de rango o conjunto de rangos numérico, como `intspan` o `floatspanset`.

- `numbers` representa cualquier tipo de conjunto o de rango numérico, como `integer`, `intset`, `intspan` o `intspanset`,

- `dates` representa cualquier tipo de tiempo con granularidad `date`, a saber `date`, `dateset`, `datespan` o `datespanset`,

- `numset` representa cualquier tipo de conjunto numérico, como `intset` o `floatset`.

- `numspans` representa cualquier tipo de rango o conjunto de rangos numérico, como `intspan` o `floatspanset`.

- `numbers` representa cualquier tipo de conjunto o de rango numérico, como `integer`, `intset`, `intspan` o `intspanset`,

- `dates` representa cualquier tipo de tiempo con granularidad `date`, a saber `date`, `dateset`, `datespan` o `datespanset`,

- `times` representa cualquier tipo de tiempo con granularidad `timestamptz`, a saber `timestamptz`, `tstzset`, `tstzspan` o `tstzspanset`,

- Un conjunto de tipos como `{set,base}` representa cualquiera de los tipos enumerados,

- `type[]` representa una matriz de `type`.

Como ejemplo, la firma del operador contiene (`@>`) es como sigue:

    {set,spans} @> {base,set,spans} → boolean

Nótese que la firma anterior es una versión abreviada de la firma más precisa a continuación

    set @> {base,set} → boolean
    spans @> {base,spans} → boolean

ya que los conjuntos y los rangos no se pueden mezclar en las operaciones y, por lo tanto, por ejemplo, no se puede preguntar si un rango contiene un conjunto. A continuación, por concisión, utilizamos el estilo abreviado de las firmas anteriores. Además, la parte de tiempo de las marcas de tiempo se omite en la mayoría de los ejemplos. Recuerde que en ese caso PostgreSQL asume el tiempo `00:00:00`.

A continuación, dado que los tipos de rango y conjunto de rangos tienen funciones y operadores similares, cuando hablamos de tipos rango nos referimos a los tipos de rango y conjuntos de rangos, a menos que nos refiramos explícitamente a los tipos de rango unitarios y a los tipos de conjunto de rangos para distinguirlos. Además, cuando nos referimos a tipos de tiempo, nos referimos a uno de los siguientes tipos: `timestamptz`, `tstzset`, `tstzspan` o `tstzspanset`.

## Entrada y salida

MobilityDB generaliza los formatos de entrada y salida Well-Known Text (WKT) y Well-Known Binary (WKB) del Open Geospatial Consortium (OGC) a para todos sus tipos. De esta forma, las aplicaciones pueden intercambiar datos entre ellas utilizando un formato de intercambio estandarizado. El formato WKT es legible por humanos, mientras que el formato WKB es más compacto y más eficiente que el formato WKT. El formato WKB se puede generar como una cadena binaria o como una cadena de caracteres codificada en ASCII hexadecimal.

Los tipos de conjunto representan un conjunto ordenado de valores diferentes. Un conjunto debe contener al menos un elemento. Ejemplos de valores de tipos de conjunto son como sigue:

    SELECT tstzset '{2001-01-01 08:00:00, 2001-01-03 09:30:00}';
    -- Conjunto unitario
    SELECT textset '{"highway"}';
    -- Conjunto erróneo: elementos desordenados
    SELECT floatset '{3.5, 1.2}';
    -- Conjunto erróneo: elementos duplicados
    SELECT geomset '{"Point(1 1)", "Point(1 1)"}';

Nótese que los elementos de los conjuntos `textset`, `geomset`, `geogset` y `npointset` deben estar delimitados entre commillas dobles. Nótese también que las geometrías y las geografías utilizan el orden definido por PostGIS.

Un valor de un tipo de rango unitario tiene dos límites, el límite inferior y el límite superior, que son valores del tipo de base subyacente. Por ejemplo, un valor del tipo `tstzspan` tiene dos límites, que son valores de `timestamptz`. Los límites pueden ser inclusivos o exclusivos. Un límite inclusivo significa que el instante límite está incluido en el rango, mientras que un límite exclusivo significa que el instante límite no está incluido en el rango. En el formato textual de un valor de un rango, los límites inferiores inclusivos y exclusivos están representados, respectivamente, por “`[`” y “`(`”. Asimismo, los límites superiores inclusivos y exclusivos se representan, respectivamente, por “`]`” y “`)`”. En un valor de un rango, el límite inferior debe ser menor o igual que el límite superior. Un valor de rango con límites iguales e inclusivos se llama rango instantáneo y corresponde a un valor del tipo de base. Ejemplos de valores de rango son como sigue:

    SELECT intspan '[1, 3)';
    SELECT floatspan '[1.5, 3.5]';
    SELECT tstzspan '[2001-01-01 08:00:00, 2001-01-03 09:30:00)';
    -- Rangos instantáneos
    SELECT intspan '[1, 1]';
    SELECT floatspan '[1.5, 1.5]';
    SELECT tstzspan '[2001-01-01 08:00:00, 2001-01-01 08:00:00]';
    -- Rango erróneo: límites inválidos
    SELECT tstzspan '[2001-01-01 08:10:00, 2001-01-01 08:00:00]';
    -- Rango erróneo: rango vacío
    SELECT tstzspan '[2001-01-01 08:00:00, 2001-01-01 08:00:00)';

Los valores de `intspan`, `bigintspan` y `datespan` son convertidos en forma normal para que los valores equivalentes tengan representaciones idénticas. En la representación canónica de estos tipos, el límite inferior es inclusivo y el límite superior es exclusivo, como se muestra en los siguientes ejemplos:

    SELECT intspan '[1, 1]';
    -- [1, 2)
    SELECT bigintspan '(1, 3]';
    --[2, 4)
    SELECT datespan '[2001-01-01, 2001-01-03]';
    -- [2001-01-01, 2001-01-04)

Un valor de un tipo de conjunto de rangos representa un conjunto ordenado de valores de rango disjuntos. Un valor de conjunto de rangos debe contener al menos un elemento, en cuyo caso corresponde a un único valor de rango. Ejemplos de valores conjunto de rangos son los siguientes:

    SELECT floatspanset '{[8.1, 8.5],[9.2, 9.4]}';
    -- Singleton spanset
    SELECT tstzspanset '{[2001-01-01 08:00:00, 2001-01-01 08:10:00]}';
    -- Erroneous spanset: unordered elements
    SELECT intspanset '{[3,4],[1,2]}';
    -- Erroneous spanset: overlapping elements
    SELECT tstzspanset '{[2001-01-01 08:00:00, 2001-01-01 08:10:00],
      [2001-01-01 08:05:00, 2001-01-01 08:15:00]}';

Los valores de los tipos conjunto de rangos son convertidos en forma normal de modo que los valores equivalentes tengan representaciones idénticas. Para ello, los valores de rango consecutivos que son adyacentes se fusionan cuando es posible. Ejemplos de transformación a forma normal son los siguientes:

    SELECT intspanset '{[1,2],[3,4]}';
    -- {[1, 5)}
    SELECT floatspanset '{[1.5,2.5],(2.5,4.5]}';
    -- {[1.5, 4.5]}
    SELECT tstzspanset '{[2001-01-01 08:00:00, 2001-01-01 08:10:00),
      [2001-01-01 08:10:00, 2001-01-01 08:10:00], (2001-01-01 08:10:00, 2001-01-01 08:20:00]}';
    -- {[2001-01-01 08:00:00+00,2001-01-01 08:20:00+00]}

Damos a continuación las funciones de entrada y salida de tipos de conjunto y de rango en formato textual (Well-Known Text o WKT) y binario (Well-Known Binary o WKB). El formato de salida predeterminado de todos los tipos de conjuntos y de rango es el formato de texto conocido. La función `asText` que se da a continuación permite determinar la salida de valores de punto flotante.

- Devuelve la representación textual conocida (Well-Known Text o WKT)

  `asText({floatset,floatspans},maxdecdigits=15) → text`

  El argumento `maxdecdigits` se puede utilizar para definir el número máximo de decimales para la salida de los valores de coma flotante (por defecto 15).

      SELECT asText(floatset '{1.123456789,2.123456789}', 3);
      -- {1.123, 2.123}
      SELECT asText(floatspanset '{[1.55,2.55],[4,5]}',0);
      -- {[2, 3], [4, 5]}

- Devuelve la representación binaria conocida (Well-Known Binary o WKB) o la representación hexadecimal binaria conocida (HexWKB)

  `asBinary({set,spans},endian text='') → bytea`

  `asHexWKB({set,spans},endian text='') → text`

  El resultado se codifica utilizando la codificación little-endian (NDR) o big-endian (XDR). Si no se especifica ninguna codificación, se utiliza la codificación de la máquina.

      SELECT asBinary(dateset '{2001-01-01, 2001-01-03}');
      -- \x01050001020000006e01000070010000
      SELECT asBinary(intspan '[1, 3)');
      -- \x011300010100000003000000
      SELECT asBinary(floatspanset '{[1, 2], [4, 5]}', 'XDR');
      -- \x00000e00000002033ff000000000000040000000000000000340100000000000004014000000000000
      SELECT asHexWKB(dateset '{2001-01-01, 2001-01-03}');
      -- 01050001020000006E01000070010000
      SELECT asHexWKB(intspan '[1, 3)');
      -- 011300010100000003000000
      SELECT asHexWKB(floatspanset '{[1, 2], [4, 5]}', 'XDR');
      -- 00000E00000002033FF000000000000040000000000000000340100000000000004014000000000000

- Entrar a partir de la representación binaria conocida (WKB) o a partir de la representación hexadecimal binaria conocida (HexWKB)

  `settypeFromBinary(bytea) → set`

  `spantypeFromBinary(bytea) → span`

  `spansettypeFromBinary(bytea) → spanset`

  `settypeFromHexWKB(text) → set`

  `spantypeFromHexWKB(text) → span`

  `spansettypeFromHexWKB(text) → spanset`

  Hay una función por tipo de conjunto o de rango, el nombre de la función tiene como prefijo el nombre del tipo.

      SELECT datesetFromBinary('\x01050001020000006e01000070010000');
      -- {2001-01-01, 2001-01-03}
      SELECT intspanFromBinary('\x011300010100000003000000');
      -- [1, 3)
      SELECT floatspansetFromBinary(
        '\x00000e00000002033ff000000000000040000000000000000340100000000000004014000000000000');
      -- {[1, 2], [4, 5]}
      SELECT datesetFromHexWKB('01050001020000006E01000070010000');
      -- {2001-01-01, 2001-01-03}
      SELECT intspanFromHexWKB('011300010100000003000000');
      -- [1, 3)
      SELECT floatspansetFromHexWKB(
        '00000E00000002033FF000000000000040000000000000000340100000000000004014000000000000');
      -- {[1, 2], [4, 5]}

## Constructores

La función constructora para los tipos de conjunto tiene un único argumento que es una matriz de valores del tipo base correspondiente. Los valores deben estar ordenados y no pueden tener nulos ni duplicados.

- Constructor para tipos de conjunto

  `set(base[]) → set`

      SELECT set(ARRAY['highway', 'primary', 'secondary']);
      -- {"highway", "primary", "secondary"}
      SELECT set(ARRAY[timestamptz '2001-01-01 08:00:00', '2001-01-03 09:30:00']);
      -- {2001-01-01 08:00:00+00, 2001-01-03 09:30:00+00}

Los tipos de rango unitarios tienen una función constructora que acepta cuatro argumentos, donde los dos últimos son opcionales. Los primeros dos argumentos especifican, respectivamente, el límite inferior y el superior, y los dos últimos argumentos son valores booleanos que indican, respectivamente, si los límites inferior y el superior son inclusivos o no. Se supone que los dos últimos argumentos son, respectivamente, verdadero y falso si no se especifican. Nótese que los rangos de enteros se transforman en forma normal, es decir, con límite inferior inclusivo y límite superior exclusivo.

- Constructor para tipos de rango

  `span(lower base,upper base,leftInc bool=true,rightInc bool=false) → span`

      SELECT span(20.5, 25);
      -- [20.5, 25)
      SELECT span(20, 25, false, true);
      -- [21, 26)
      SELECT span(timestamptz '2001-01-01 08:00:00', '2001-01-03 09:30:00', false, true);
      -- (2001-01-01 08:00:00, 2001-01-03 09:30:00]

La función constructora para los tipos de conjuntos de rangos tiene un solo argumento que es una matriz de rangos del mismo subtipo.

- Constructor for conjunto de rangos

  `spanset(span[]) → spanset`

      SELECT spanset(ARRAY[intspan '[10,12]', '[13,15]']);
      -- {[10, 16)}
      SELECT spanset(ARRAY[floatspan '[10.5,12.5]', '[13.5,15.5]']);
      -- {[10.5, 12.5], [13.5, 15.5]}
      SELECT spanset(ARRAY[tstzspan '[2001-01-01 08:00, 2001-01-01 08:10]',
        '[2001-01-01 08:20, 2001-01-01 08:40]']);
      -- {[2001-01-01 08:00, 2001-01-01 08:10], [2001-01-01 08:20, 2001-01-01 08:40]};

## Conversión de tipos

Los valores de los tipos de conjunto y de rango se pueden convertir entre sí o convertirse a tipos de rango de PostgreSQL y desde ellos mediante la función `CAST` o mediante la notación `::`.

- Convertir un valor de base en un valor de conjunto, rango o conjunto de rangos

  `base::{set,span,spanset}`

  `set(base) → set`

  `span(base) → span`

  `spanset(base) → spanset`

      SELECT CAST(timestamptz '2001-01-01 08:00:00' AS tstzset);
      -- {2001-01-01 08:00:00}
      SELECT timestamptz '2001-01-01 08:00:00'::tstzspan;
      -- [2001-01-01 08:00:00, 2001-01-01 08:00:00]
      SELECT spanset(timestamptz '2001-01-01 08:00:00');
      -- {[2001-01-01 08:00:00, 2001-01-01 08:00:00]}

- Convertir un valor de conjunto en un valor de conjunto de rangos

  `set::spanset`

  `spanset(set) → spanset`

      SELECT spanset(tstzset '{2001-01-01 08:00:00, 2001-01-01 08:15:00,
        2001-01-01 08:25:00}');
      /* {[2001-01-01 08:00:00, 2001-01-01 08:00:00],
         [2001-01-01 08:15:00, 2001-01-01 08:15:00],
         [2001-01-01 08:25:00, 2001-01-01 08:25:00]} */

- Convertir un valor de rango a un valor de conjunto de rangos

  `span::spanset`

  `spanset(span) → spanset`

      SELECT floatspan '[1.5,2.5]'::floatspanset;
      -- {[1.5, 2.5]}
      SELECT tstzspan '[2001-01-01 08:00:00, 2001-01-01 08:30:00)'::tstzspanset;
      -- {[2001-01-01 08:00:00, 2001-01-01 08:30:00)}

- Convertir un conjunto de valores o un conjunto de rangos a un rango, ignorando las posibles brechas de tiempo

  `{set,spanset}::span`

  `span({set,spanset}) → span`

      SELECT span(dateset '{2001-01-01, 2001-01-03, 2001-01-05}');
      -- [2001-01-01, 2001-01-06)
      SELECT span(tstzspanset '{[2001-01-01, 2001-01-02), [2001-01-03, 2001-01-04)}');
      -- [2001-01-01, 2001-01-04)

- Convertir un valor de de rango en MobilityDB hacia y desde un valor de rango de PostgreSQL

  `span::range`

  `range::span`

  `range(span) → range`

  `span(range) → span`

  Nótese que los valores de rango en PostgreSQL aceptan rangos vacíos y rangos con límites infinitos, que no están permitidos como valores de rango en MobilityDB

      SELECT intspan '[10, 20)'::int4range;
      -- [10,20)
      SELECT tstzspan '[2001-01-01 08:00:00, 2001-01-01 08:30:00)'::tstzrange;
      -- ["2001-01-01 08:00:00","2001-01-01 08:30:00")
      SELECT int4range '[10, 20)'::intspan;
      -- [10,20)
      SELECT int4range 'empty'::intspan;
      -- ERROR:  Range cannot be empty
      SELECT int4range '[10,)'::intspan;
      -- ERROR:  Range bounds cannot be infinite
      SELECT tstzrange '[2001-01-01 08:00:00, 2001-01-01 08:30:00)'::tstzspan;
      -- [2001-01-01 08:00:00, 2001-01-01 08:30:00)

- Convertir un valor de conjunto de rangos de MobilityDB hacia y desde un valor de multirango de PostgreSQL

  `spanset::multirange`

  `multirange::spanset`

  `multirange(spanset) → multirange`

  `spanset(multirange) → spanset`

      SELECT intspanset '{[1,2],[4,5]}'::int4multirange;
      -- {[1,3),[4,6)}
      SELECT tstzspanset '{[2001-01-01,2001-01-02],[2001-01-04,2001-01-05]}'::tstzmultirange;
      -- {[2001-01-01,2001-01-02],[2001-01-04,2001-01-05]}
      SELECT int4multirange '{[1,2],[4,5]}'::intspanset;
      -- {[1, 3), [4, 6)}
      SELECT tstzmultirange '{[2001-01-01,2001-01-02],[2001-01-04,2001-01-05]}'::tstzspanset;
      -- {[2001-01-01, 2001-01-02], [2001-01-04, 2001-01-05]}

## Accesores

- Devuelve el tamaño de la memoria en bytes

  `memSize({set,spanset}) → integer`

      SELECT memSize(tstzset '{2001-01-01, 2001-01-02, 2001-01-03}');
      -- 48
      SELECT memSize(tstzspanset '{[2001-01-01, 2001-01-02], [2001-01-03, 2001-01-04],
        [2001-01-05, 2001-01-06]}');
      -- 112

- Devuelve el límite inferior o superior

  `lower(spans) → base`

  `upper(spans) → base`

      SELECT lower(tstzspan '[2001-01-01, 2001-01-05)');
      -- 2001-01-01
      SELECT lower(intspanset '{[1,2],[4,5]}');
      --  1

      SELECT lower(tstzspan '[2001-01-01, 2001-01-05)');
      -- 2001-01-01
      SELECT upper(intspanset '{[1,2],[4,5]}');
      --  6
      SELECT lower(tstzspan '[2001-01-01, 2001-01-05)');
      -- 2001-01-01
      SELECT lower(intspanset '{[1,2],[4,5]}');
      --  1

      SELECT upper(floatspan '[20.5, 25.3)');
      -- 25.3
      SELECT upper(tstzspan '[2001-01-01, 2001-01-05)');
      -- 2001-01-05

- ¿Es el límite inferior or superior inclusivo?

  `lowerInc(spans) → boolean`

  `upperInc(spans) → boolean`

      SELECT lowerInc(datespan '[2001-01-01, 2001-01-05)');
      -- true
      SELECT lowerInc(intspanset '{[1,2],[4,5]}');
      -- true

      SELECT lowerInc(tstzspan '[2001-01-01, 2001-01-05)');
      -- true
      SELECT upperInc(intspanset '{[1,2],[4,5]}');
      -- false
      SELECT upper(floatspan '[20.5, 25.3]');
      -- true
      SELECT upperInc(tstzspan '[2001-01-01, 2001-01-05)');
      -- false

- Devuelve el ancho del rango como un número de punto flotante

  `width(numspan) → float`

  `width(numspanset,boundspan=false) → float`

  Se puede establecer a verdadero un parámetro adicional para calcular el ancho del rango delimitador, ignorando así las posibles brechas de valors

      SELECT width(floatspan '[1, 3)');
      -- 2
      SELECT width(intspanset '{[1,3),[5,7)}');
      -- 4
      SELECT width(intspanset '{[1,3),[5,7)}', true);
      -- 6

- Devuelve el rango de tiempo

  `duration({datespan,tstzspan}) → interval`

  `duration({datespanset,tstzspanset},boundspan bool=false) → interval`

  Se puede establecer a verdadero un parámetro adicional para calcular la duración en el rango delimitador, ignorando así las posibles brechas de tiempo

      SELECT duration(datespan '[2001-01-01, 2001-01-03)');
      -- 2 days
      SELECT duration(tstzspanset '{[2001-01-01, 2001-01-03), [2001-01-04, 2001-01-05)}');
      -- 3 days
      SELECT duration(tstzspanset '{[2001-01-01, 2001-01-03), [2001-01-04, 2001-01-05)}', true);
      -- 4 days

- Devuelve el número de valores o los valores

  `numValues(set) → integer`

  `getValues(set) → base[]`

      SELECT numValues(intset '{1,3,5,7}');
      -- 4
      SELECT getValues(tstzset '{2001-01-01, 2001-01-03, 2001-01-05, 2001-01-07}');
      -- {"2001-01-01", "2001-01-03", "2001-01-05", "2001-01-07"}

- Devuelve el valor inicial, final o enésimo

  `startValue(set) → base`

  `endValue(set) → base`

  `valueN(set,integer) → base`

      SELECT startValue(intset '{1,3,5,7}');
      -- 1
      SELECT endValue(dateset '{2001-01-01, 2001-01-03, 2001-01-05, 2001-01-07}');
      -- 2001-01-07
      SELECT valueN(floatset '{1,3,5,7}',2);
      -- 3

- Devuelve el número de rangos o los rangos

  `numSpans(spanset) → integer`

  `spans(spanset) → span[]`

      SELECT numSpans(intspanset '{[1,3),[4,5),[6,7)}');
      -- 3
      SELECT numSpans(datespanset '{[2001-01-01, 2001-01-03), [2001-01-04, 2001-01-05),
        [2001-01-06, 2001-01-07)}');
      -- 3
      SELECT spans(floatspanset '{[1,3),[4,4],[6,7)}');
      -- {"[1,3)","[4,4]","[6,7)"}
      SELECT spans(tstzspanset '{[2001-01-01, 2001-01-03), [2001-01-04, 2001-01-04],
        [2001-01-05, 2001-01-06)}');
      -- {"[2001-01-01,2001-01-03)", "[2001-01-04,2001-01-04]", "[2001-01-05,2001-01-06)"}

- Devuelve el rango inicial, final o enésimo

  `startSpan(spanset) → span`

  `endSpan(spanset) → span`

  `spanN(spanset,integer) → span`

      SELECT startSpan(intspanset '{[1,3),[4,5),[6,7)}');
      -- [1,3)
      SELECT startSpan(datespanset '{[2001-01-01, 2001-01-03), [2001-01-04, 2001-01-05),
        [2001-01-06, 2001-01-07)}');
      -- [2001-01-01,2001-01-03)

      SELECT endSpan(floatspanset '{[1,3),[4,4],[6,7)}');
      -- [6,7)
      SELECT endSpan(tstzspanset '{[2001-01-01, 2001-01-03), [2001-01-04, 2001-01-04],
        [2001-01-05, 2001-01-06)}');
      -- [2001-01-05,2001-01-06)

      SELECT spanN(floatspanset '{[1,3),[4,4],[6,7)}',2);
      -- [4,4]
      SELECT spanN(tstzspanset '{[2001-01-01, 2001-01-03), [2001-01-04, 2001-01-04],
        [2001-01-05, 2001-01-06)}', 2);
      -- [2001-01-04,2001-01-04]

- Devuelve el (number of) different dates

  `numDates(datespanset) → integer`

  `dates(datespanset) → dateset`

      SELECT numDates(datespanset '{[2001-01-01, 2001-01-02), [2001-01-03, 2001-01-04)}');
      -- 4
      SELECT dates(datespanset '{[2001-01-01, 2001-01-02), [2001-01-03, 2001-01-04)}');
      -- {2001-01-01, 2001-01-02, 2001-01-03, 2001-01-04}

- Devuelve el start, end, or n-th date

  `startDate(datespanset) → date`

  `endDate(datespanset) → date`

  `dateN(datespanset,integer) → date`

  The functions do not take into account whether the bounds are inclusive or not.

      SELECT startDate(datespanset '{[2001-01-01, 2001-01-02), [2001-01-03, 2001-01-04)}');
      -- 2001-01-01
      SELECT endDate(datespanset '{[2001-01-01, 2001-01-03), (2001-01-03, 2001-01-05)}');
      -- 2001-01-05
      SELECT dateN(datespanset '{[2001-01-01, 2001-01-03), (2001-01-03, 2001-01-05)}', 3);
      -- 2001-01-05

- Devuelve el número o las marcas de tiempo diferentes

  `numTimestamps(tstzspanset) → integer`

  `timestamps(tstzspanset) → tstzset`

      SELECT numTimestamps(tstzspanset '{[2001-01-01, 2001-01-03), (2001-01-03, 2001-01-05)}');
      -- 3
      SELECT timestamps(tstzspanset '{[2001-01-01, 2001-01-03), (2001-01-03, 2001-01-05)}');
      -- {"2001-01-01 00:00:00", "2001-01-03 00:00:00", "2001-01-05 00:00:00"}

- Devuelve la marca de tiempo inicial, final, o enésima

  `startTimestamp(tstzspanset) → timestamptz`

  `endTimestamp(tstzspanset) → timestamptz`

  `timestampN(tstzspanset,integer) → timestamptz`

  The functions do not take into account whether the bounds are inclusive or not.

      SELECT startTimestamp(tstzspanset '{[2001-01-01, 2001-01-02), [2001-01-03, 2001-01-04)}');
      -- 2001-01-01
      SELECT endTimestamp(tstzspanset '{[2001-01-01, 2001-01-03), (2001-01-03, 2001-01-05)}');
      -- 2001-01-05
      SELECT timestampN(tstzspanset '{[2001-01-01, 2001-01-03), (2001-01-03, 2001-01-05)}', 3);
      -- 2001-01-05

## Transformaciones

- Expandir o reducir los límites de un rango con un valor o un intervalo de tiempo

  `expand(numspan,base) → numspan`

  `expand(tstzspan,interval) → tstzspan`

  La función devuelve NULL si el valor o intervalo dado como segundo argumento es negativo y el rango resultante de desplazar los límites con el argumento está vacío.

      SELECT expand(floatspan '[1, 3]', 1);
      -- [0, 4]
      SELECT expand(floatspan '[1, 3]', -1);
      -- [2, 2]
      SELECT expand(floatspan '[1, 3)', -1);
      -- NULL
      SELECT expand(tstzspan '[2001-01-01, 2001-01-03]', interval '1 day');
      -- [2000-12-31, 2001-01-04]
      SELECT expand(tstzspan '[2001-01-01, 2001-01-03]', interval '-1 day');
      -- [2001-01-02, 2001-01-02]
      SELECT expand(tstzspan '[2001-01-01, 2001-01-03]', interval '-2 day');
      -- NULL

- Desplazar con un valor o rango de tiempo

  `shift(numbers,base) → numbers`

  `shift(dates,integer) → dates`

  `shift(times,interval) → times`

      SELECT shift(dateset '{2001-01-01, 2001-01-03, 2001-01-05}', 1);
      -- {2001-01-02, 2001-01-04, 2001-01-06}
      SELECT shift(intspan '[1, 4)', -1);
      -- [0, 3)
      SELECT shift(tstzspan '[2001-01-01, 2001-01-03]', interval '1 day');
      -- [2001-01-02, 2001-01-04]
      SELECT shift(floatspanset '{[1, 2], [3, 4]}', -1);
      -- {[0, 1], [2, 3]}
      SELECT shift(tstzspanset '{[2001-01-01, 2001-01-03], [2001-01-04, 2001-01-05]}',
        interval '1 day');
      -- {[2001-01-02, 2001-01-04], [2001-01-05, 2001-01-06]}

- Escalear con un valor o un rango de tiempo

  `scale(numbers,base) → numbers`

  `scale(dates,integer) → dates`

  `scale(times,interval) → times`

  Si el ancho o el lapso de tiempo del valor de entrada es cero (por ejemplo, para un conjunto de marcas de tiempo único), el resultado es el valor de entrada. El valor o rango de tiempo dado debe ser estrictamente mayor que cero.

      SELECT scale(tstzset '{2001-01-01}', interval '1 day');
      -- {2001-01-01}
      SELECT scale(tstzset '{2001-01-01, 2001-01-03, 2001-01-05}', '2 days');
      -- {2001-01-01, 2001-01-02, 2001-01-03}
      SELECT scale(intspan '[1, 4)', 4);
      -- [1, 6)
      SELECT scale(datespan '[2001-01-01, 2001-01-04)', 4);
      -- [2001-01-01, 2001-01-06)
      SELECT scale(tstzspan '[2001-01-01, 2001-01-03]', '1 day');
      -- [2001-01-01, 2001-01-02]
      SELECT scale(floatspanset '{[1, 2], [3, 4]}', 6);
      -- {[1, 3], [5, 7]}
      SELECT scale(tstzspanset '{[2001-01-01, 2001-01-03], [2001-01-04, 2001-01-05]}', '1 day');
      -- {[2001-01-01 00:00:00, 2001-01-01 12:00:00],
        [2001-01-01 18:00:00, 2001-01-02 00:00:00]}
      SELECT scale(tstzset '{2001-01-01}', '-1 day');
      -- ERROR:  The duration must be a positive interval: -1 days

- Desplazar y escalear con los valores o rangos de tiempo

  `shiftScale(numbers,base,base) → numbers`

  `shiftScale(dates,integer,integer) → dates`

  `shiftScale(times,interval,interval) → times`

  Estas funciones combinan las funciones `shift` y `scale`.

      SELECT shiftScale(tstzset '{2001-01-01}', '1 day', '1 day');
      -- {2001-01-02}
      SELECT shiftScale(tstzset '{2001-01-01, 2001-01-03, 2001-01-05}', '1 day','2 days');
      -- {2001-01-02, 2001-01-03, 2001-01-04}
      SELECT shiftScale(intspan '[1, 4)', -1, 4);
      -- [0, 5)
      SELECT shiftScale(datespan '[2001-01-01, 2001-01-04)', -1, 4);
      -- [2001-12-31, 2001-01-05)
      SELECT shiftScale(tstzspan '[2001-01-01, 2001-01-03]', '1 day', '1 day');
      -- [2001-01-02, 2001-01-03]
      SELECT shiftScale(floatspanset '{[1, 2], [3, 4]}', -1, 6);
      -- {[0, 2], [4, 6]}
      SELECT shiftScale(tstzspanset '{[2001-01-01, 2001-01-03], [2001-01-04, 2001-01-05]}',
        '1 day', '1 day');
      /* {[2001-01-02 00:00:00, 2001-01-02 12:00:00],
         [2001-01-02 18:00:00, 2001-01-03 00:00:00]} */

- Redondear al entero inferior o superior

  `floor({floatset,floatspans}) → {floatset,floatspans}`

  `ceil({floatset,floatspans}) → {floatset,floatspans}`

      SELECT floor(floatset '{1.5,2.5}');
      -- {1, 2}
      SELECT ceil(floatspan '[1.5,2.5)');
      -- [2, 3)
      SELECT floor(floatspan '(1.5, 1.6)');
      -- [1, 1]
      SELECT ceil(floatspanset '{[1.5, 2.5],[3.5,4.5]}');
      -- {[2, 3], [4, 5]}

- Redondear a un número de decimales

  `round({floatset,floatspans},integer=0) → {floatset,floatspans}`

      SELECT round(floatset '{1.123456789,2.123456789}', 3);
      -- {1.123, 2.123}
      SELECT round(floatspan '[1.123456789,2.123456789)', 3);
      -- [1.123,2.123)
      SELECT round(floatspan '[1.123456789, inf)', 3);
      -- [1.123,Infinity)
      SELECT round(floatspanset '{[1.123456789, 2.123456789],[3.123456789,4.123456789]}', 3);
      -- {[1.123, 2.123], [3.123, 4.123]}

- Convertir a grados o radianes

  `degrees({floatset,floatspans}, normalize=false) → {floatset,floatspans}`

  `radians({floatset,floatspans}) → {floatset,floatspans}`

  El parámetro adicional en la función `degrees` puede ser utilizado para normalizar los valores entre 0 y 360 grados.

      SELECT round(degrees(floatset '{0, 0.5, 0.7, 1.0}', true), 3);
      -- {0, 28.648, 40.107, 57.296}
      SELECT round(radians(floatspanset '{[0, 45], [90, 135]}'), 3);
      -- {[0, 0.785], [1.571, 2.356]}

- Transformar en minúsculas, majúsculas o initcap

  `lower(textset) → textset`

  `upper(textset) → textset`

  `initcap(textset) → textset`

      SELECT lower(textset '{"AAA", "BBB", "CCC"}');
      -- {"aaa", "bbb", "ccc"}
      SELECT upper(textset '{"aaa", "bbb", "ccc"}');
      -- {"AAA", "BBB", "CCC"}
      SELECT initcap(textset '{"aaa", "bbb", "ccc"}');
      -- {"Aaa", "Bbb", "Ccc"}

- Concatenación de texto

  `{text,textset} || {text,textset} → textset`

      SELECT textset '{aaa, bbb}' || text 'XX';
      -- {"aaaXX", "bbbXX"}
      SELECT text 'XX' || textset '{aaa, bbb}';
      -- {"XXaaa", "XXbbb"}

- Establecer la precisión temporal del valor de tiempo al rango con respecto al origen

  `tprecision(times,interval,origin timestamptz=’2000-01-03’) → times`

  Si el origen no se especifica, su valor se establece por defecto en lunes 3 de enero de 2000.

      SELECT tprecision(timestamptz '2001-12-03', '30 days');
      -- 2001-11-23
      SELECT tprecision(timestamptz '2001-12-03', '30 days', '2001-12-01');
      -- 2001-12-01
      SELECT tprecision(tstzset '{2001-01-01 08:00, 2001-01-01 08:10, 2001-01-01 09:00,
        2001-01-01 09:10}', '1 hour');
      -- {"2001-01-01 08:00:00+01", "2001-01-01 09:00:00+01"}
      SELECT tprecision(tstzspan '[2001-12-01 08:00, 2001-12-01 09:00]', '1 day');
      -- [2001-12-01, 2001-12-02)
      SELECT tprecision(tstzspan '[2001-12-01 08:00, 2001-12-15 09:00]', '1 day');
      -- [2001-12-01, 2001-12-16)
      SELECT tprecision(tstzspanset '{[2001-12-01 08:00, 2001-12-01 09:00],
        [2001-12-01 10:00, 2001-12-01 11:00]}', '1 day');
      -- {[2001-12-01, 2001-12-02)}
      SELECT tprecision(tstzspanset '{[2001-12-01 08:00, 2001-12-01 09:00],
        [2001-12-01 10:00, 2001-12-01 11:00]}', '1 day');
      -- {[2001-12-01, 2001-12-02)}

## Sistema de referencia espacial

- Devuelve o especifica el identificador de referencia espacial

  `SRID(spatialset) → integer`

  `setSRID(spatialset) → spatialset`

      SELECT SRID(geomset '{"Point(1 1)", "Point(2 2)"}');
      -- 0
      SELECT SRID(geogset '{"Linestring(1 1,2 2)","Polygon((1 1,1 2,2 2,2 1,1 1))"}');
      -- 4326
      SELECT SRID(geomset 'SRID=5676;{"Linestring(1 1,2 2)","Polygon((1 1,1 2,2 2,2 1,1 1))"}');
      -- 5676
      SELECT asEWKT(setSRID(geomset '{Point(1 1), Point(2 2)}', 5676));
      -- SRID=5676;{"POINT(1 1)", "POINT(2 2)"}
      SELECT asEWKT(setSRID(poseset '{"Pose(Point(1 1),1)", "Pose(Point(2 2),3)"}', 5676));
      -- SRID=5676;{"Pose(POINT(2 2),3)", "Pose(POINT(1 1),1)"}

- Transformar a una referencia espacial diferente

  `transform(spatialset,to_srid integer) → spatialset`

  `transformPipeline(spatialset,pipeline text,to_srid integer,is_forward bool=true) →`

  `spatialset`

  La función `transform` especifica la transformación con un SRID de destino. Se genera un error cuando el conjunto tiene un SRID desconocido (representado por 0). La función `transformPipeline` especifica la transformación con una canalización de transformación de coordenadas en el siguiente formato:

  `urn:ogc:def:coordinateOperation:AUTHORITY::CODE`

  El SRID del conjunto de entrada se ignora y el SRID de la conjunto de salida se establecerá en cero a menos que se proporcione un valor a través del parámetro opcional `to_srid`. Como se indica en el último parámetro, la canalización se ejecuta de forma predeterminada en dirección hacia adelante; al establecer el parámetro en falso, la canalización se ejecuta en la dirección inversa.

      SELECT asEWKT(transform(geomset 'SRID=4326;{Point(2.340088 49.400250),
        Point(6.575317 51.553167)}', 3812), 6);
      -- SRID=3812;{"POINT(502773.429981 511805.120402)", "POINT(803028.908265 751590.742629)"}
      WITH test(geoset, pipeline) AS (
        SELECT geogset 'SRID=4326;{"Point(4.3525 50.846667 100.0)",
          "Point(-0.1275 51.507222 100.0)"}',
          text 'urn:ogc:def:coordinateOperation:EPSG::16031' )
      SELECT asEWKT(transformPipeline(transformPipeline(geoset, pipeline, 4326), pipeline,
        4326, false), 6)
      FROM test;
      -- SRID=4326;{"POINT Z (4.3525 50.846667 100)", "POINT Z (-0.1275 51.507222 100)"}

## Operaciones de conjuntos

Los tipos de conjunto y de rango tienen operadores de conjuntos asociados, a saber, unión, diferencia e intersección, que se representan, respectivamente, por `+`, `-` y `*` . Los operadores de conjunto para los tipos de rango y tiempo se dan a continuación.

- Unión, diferencia o intersección de conjuntos o de rangos

  `set {+, - , *} set → set`

  `spans {+, - , *} spans → spans`

      SELECT dateset '{2001-01-01, 2001-01-03, 2001-01-05}' +
        dateset '{2001-01-03, 2001-01-06}';
      -- {2001-01-01, 2001-01-03, 2001-01-05, 2001-01-06}
      SELECT intspan '[1, 3)' + intspan '[3, 5)';
      -- [1, 5)
      SELECT floatspan '[1, 3)' + floatspan '[4, 5)';
      -- {[1, 3), [4, 5)}
      SELECT tstzspanset '{[2001-01-01, 2001-01-03), [2001-01-04, 2001-01-05)}' +
        tstzspan '[2001-01-03, 2001-01-04)';
      -- {[2001-01-01, 2001-01-05)}

      SELECT intset '{1, 3, 5}' - intset '{3, 6}';
      -- {1, 5}
      SELECT datespan '[2001-01-01, 2001-01-05)' - datespan '[2001-01-03, 2001-01-07)';
      -- {[2001-01-01, 2001-01-03)}
      SELECT floatspan '[1, 5]' - floatspan '[3, 4]';
      -- {[1, 3), (4, 5]}
      SELECT tstzspanset '{[2001-01-01, 2001-01-06], [2001-01-07, 2001-01-10]}' -
        tstzspanset '{[2001-01-02, 2001-01-03], [2001-01-04, 2001-01-05],
        [2001-01-08, 2001-01-09]}';
      /* {[2001-01-01,2001-01-02), (2001-01-03,2001-01-04), (2001-01-05,2001-01-06],
         [2001-01-07,2001-01-08), (2001-01-09,2001-01-10]} */

      SELECT tstzset '{2001-01-01, 2001-01-03}' * tstzset '{2001-01-03, 2001-01-05}';
      -- {2001-01-03}
      SELECT intspan '[1, 5)' * intspan '[3, 6)';
      -- [3, 5)
      SELECT floatspanset '{[1, 5),[6, 8)}' * floatspan '[1, 6)';
      -- {[3, 5)}
      SELECT tstzspan '[2001-01-01, 2001-01-05)' * tstzspan '[2001-01-03, 2001-01-07)';
      -- [2001-01-03, 2001-01-05)

## Operaciones de cuadro delimitador

### Operaciones topológicas

A continuación se presentan los operadores topológicos disponibles para los tipos de conjunto y de rango.

- ¿Se superponen los valores (tienen valores en común)?

  `{set,spans} && {set,spans} → boolean`

      SELECT intset '{1, 3}' && intset '{2, 3, 4}';
      -- true
      SELECT floatspan '[1, 3)' && floatspan '[3, 4)';
      -- false
      SELECT floatspanset '{[1, 5),[6, 8)}' && floatspan '[1, 6)';
      -- true
      SELECT tstzspan '[2001-01-01, 2001-01-05)' && tstzspan '[2001-01-02, 2001-01-07)';
      -- true

- ¿Contiene el primer valor el segundo?

  `{set,spans} @> {base,set,span} → boolean`

      SELECT floatset '{1.5, 2.5}' @> 2.5;
      -- true
      SELECT tstzspan '[2001-01-01, 2001-05-01)' @> timestamptz '2001-02-01';
      -- true
      SELECT floatspanset '{[1, 2),(2, 3)}' @> 2.0;
      -- false

- ¿Está el primer valor contenido en el segundo?

  `{base,set,spans} <@ {set,spans} → boolean`

      SELECT timestamptz '2001-01-10' <@ tstzspan '[2001-01-01, 2001-05-01)';
      -- true
      SELECT floatspan '[2, 5]' <@ floatspan '[1, 5)';
      -- false
      SELECT floatspanset '{[1,2],[3,4]}' <@ floatspan '[1, 6]';
      -- true
      SELECT tstzspan '[2001-02-01, 2001-03-01)' <@ tstzspan '[2001-01-01, 2001-05-01)';
      -- true

- ¿Es el primer valor adyacente al segundo?

  `spans -|- spans → boolean`

      SELECT intspan '[2, 6)' -|- intspan '[6, 7)';
      -- true
      SELECT floatspan '[2, 5)' -|- floatspan '(5, 6)';
      -- false
      SELECT floatspanset '{[2, 3],[4, 5)}' -|- floatspan '(5, 6)';
      -- true
      SELECT tstzspan '[2001-01-01, 2001-01-05)' -|- tstzset '{2001-01-05, 2001-01-07}';
      -- true
      SELECT tstzspanset '{[2001-01-01, 2001-01-02]}' -|- tstzspan '[2001-01-02, 2001-01-03)';
      -- false

### Operaciones de posición

Los operadores de posición disponibles para los tipos de conjunto y de rango se dan a continuación. Observe que los operadores para tipos de tiempo tienen un `#` adicional para distinguirlos de los operadores para tipos de números.

- ¿Está el primer valor estrictamente a la izquierda del segundo?

  `numbers << numbers → boolean`

  `times <<# times → boolean`

      SELECT intspan '[15, 20)' << 20;
      -- true
      SELECT intspanset '{[15, 17],[18, 20)}' << 20;
      -- true
      SELECT floatspan '[15, 20)' << floatspan '(15, 20)';
      -- false
      SELECT dateset '{2001-01-01, 2001-01-02}' <<# dateset '{2001-01-03, 2001-01-05}';
      -- true

- ¿Está el primer valor estrictamente a la derecha del segundo?

  `numbers >> numbers → boolean`

  `times #>> times → boolean`

      SELECT intspan '[15, 20)' >> 10;
      -- true
      SELECT floatspan '[15, 20)' >> floatspan '[5, 10]';
      -- true
      SELECT floatspanset '{[15, 17], [18, 20)}' >> floatspan '[5, 10]';
      -- true
      SELECT tstzspan '[2001-01-04, 2001-01-05)' #>>
        tstzspanset '{[2001-01-01, 2001-01-04), [2001-01-05, 2001-01-06)}';
      -- true

- ¿No está el primer valor a la derecha del segundo?

  `numbers &< numbers → boolean`

  `times &<# times → boolean`

      SELECT intspan '[15, 20)' &< 18;
      -- false
      SELECT intspanset '{[15, 16],[17, 18)}' &< 18;
      -- true
      SELECT floatspan '[15, 20)' &< floatspan '[10, 20]';
      -- true
      SELECT dateset '{2001-01-02, 2001-01-05}' &<# dateset '{2001-01-01, 2001-01-04}';
      -- false

- ¿No está el primer valor a la izquierda del segundo?

  `numbers &> numbers → boolean`

  `times #&> times → boolean`

      SELECT intspan '[15, 20)' &> 30;
      -- true
      SELECT floatspan '[1, 6]' &> floatspan '(1, 3)';
      -- false
      SELECT floatspanset '{[1, 2],[3, 4]}' &> floatspan '(1, 3)';
      -- false
      SELECT timestamp '2001-01-01' #&> tstzspan '[2001-01-01, 2001-01-05)';
      -- true

### Operaciones de división

Al crear índices para tipos de conjuntos o conjunto de rangos, lo que se almacena en el índice no es el valor real, sino un cuadro delimitador que representa el valor. En este caso, el índice proporcionará una lista de valores candidatos que pueden satisfacer el predicado de la consulta, y se necesita un segundo paso para filtrar los valores candidatos calculando el predicado de la consulta sobre los valores reales.

Sin embargo, cuando los cuadros delimitadores tienen un gran espacio vacío no cubierto por los valores reales, el índice generará muchos valores candidatos que no satisfacen el predicado de la consulta, lo que reduce la eficiencia del índice. En estas situaciones, puede ser mejor representar un valor no con un cuadro delimitador único, sino con múltiples cuadros delimitadores. Esto aumenta considerablemente la eficiencia del índice, siempre que el índice sea capaz de gestionar múltiples cuadros delimitadores por valor. Las siguientes funciones se utilizan para generar múltiples rangos a partir de un único valor de conjunto o conjunto de rangos.

- Devuelve una matriz de N rangos obtenida fusionando los elementos de un conjunto o los rangos de un conjunto de rangos

  `splitNSpans(set, integer) → span[]`

  `splitNSpans(spanset, integer) → span[]`

  El último argumento especifica el número de rangos de salida. Si el número de elementos o rangos de entrada es menor que el número especificado, la matriz resultante tendrá un rango por elemento o rango de entrada. De lo contrario, el número especificado de rangos de salida se obtendrá fusionando elementos o rangos de entrada consecutivos.

      SELECT splitNSpans(intset '{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}', 1);
      /* {"[1, 11)"} */
      SELECT splitNSpans(intset '{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}', 3);
      -- {"[1, 5)","[5, 8)","[8, 11)"}
      SELECT splitNSpans(intset '{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}', 6);
      -- {"[1, 3)","[3, 5)","[5, 7)","[7, 9)","[9, 10)","[10, 11)"}
      SELECT splitNSpans(intset '{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}', 12);
      /* {"[1, 2)","[2, 3)","[3, 4)","[4, 5)","[5, 6)","[6, 7)","[7, 8)","[8, 9)",
          "[9, 10)","[10, 11)"} */

      SELECT splitNSpans(intspanset '{[1, 2), [3, 4), [5, 6), [7, 8), [9, 10)}');
      -- {"[1, 2)","[3, 4)","[5, 6)","[7, 8)","[9, 10)"}
      SELECT splitNSpans(floatspanset '{[1, 2), [3, 4), [5, 6), [7, 8), [9, 10)}', 3);
      -- {"[1, 4)","[5, 8)","[9, 10)"}
      SELECT splitNSpans(datespanset '{[2000-01-01, 2000-01-04), [2000-01-05, 2000-01-10)}', 3);
      -- {"[2000-01-01, 2000-01-04)","[2000-01-05, 2000-01-10)"}

- Devuelve una matriz de rangos obtenida fusionando N elementos consecutivos de un conjunto o N rangos consecutivos de un conjunto de rangos

  `splitEachNSpans(set, integer) → span[]`

  `splitEachNSpans(spanset, integer) → span[]`

  El último argumento especifica el número de elementos de entrada que se fusionan para producir un rango de salida. Si la cantidad de elementos de entrada es menor que el número especificado, la matriz resultante tendrá un rango de salida por elemento. De lo contrario, la cantidad especificada de elementos de entrada consecutivos se fusionará en un único rango de salida en la respuesta. Observe que, a diferencia de la función `splitNSpans`, el número de rangos en el resultado depende del número de elementos o de rangos de entrada.

      SELECT splitEachNSpans(intset '{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}', 1);
      /* {"[1, 2)","[2, 3)","[3, 4)","[4, 5)","[5, 6)","[6, 7)","[7, 8)","[8, 9)",
          "[9, 10)","[10, 11)"} */
      SELECT splitEachNSpans(intspanset '{[1, 2), [3, 4), [5, 6), [7, 8), [9, 10)}', 3);
      -- {"[1, 6)","[7, 10)"}
      SELECT splitEachNSpans(intset '{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}', 6);
      -- {"[1, 7)","[7, 11)"}
      SELECT splitEachNSpans(intset '{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}', 12);
      -- {"[1, 11)"}

## Operaciones de distancia

El operador de distancia `<->` para los tipos de rango o de tiempo considera el lapso o período delimitador y devuelve la distancia más pequeña entre los dos valores. En el caso de valores de tiempo, el operador devuelve la cantidad de días o la cantidad de segundos entre los dos valores de tiempo. El operador de distancia también se puede usar para búsquedas de vecinos más cercanos utilizando un índice GiST o SP-GiST (ver setspan_indexing).

- Devuelve la distancia mínima

  `numbers <-> numbers → base`

  `dates <-> dates → integer`

  `times <-> times → float`

      SELECT 3 <-> intspan '[6, 8)';
      -- 3
      SELECT floatspan '[1, 3]' <-> floatspan '(5.5, 7]';
      -- 2.5
      SELECT floatspan '[1, 3]' <-> floatspanset '{(5.5, 7],[8, 9]}';
      -- 2.5
      SELECT tstzspan '[2001-01-02, 2001-01-06)' <-> timestamptz '2001-01-07';
      -- 86400
      SELECT dateset '{2001-01-01, 2001-01-03, 2001-01-05}' <->
        dateset '{2001-01-02, 2001-01-04}';
      --  0

## Comparaciones

Los operadores de comparación (`=`, `<`, etc.) requieren que los argumentos izquierdo y derecho sean del mismo tipo. Exceptuando la igualdad y la no igualdad, los otros operadores de comparación no son útiles en el mundo real, pero permiten construir índices de árbol B en tipos de rango o de tiempo. Para los valores de rango, los operadores comparan primero el límite inferior y luego el límite superior. Para los valores de conjunto de marcas de tiempo y conjunto de períodos, los operadores comparan primero los períodos delimitadores y, si son iguales, comparan los primeros N instantes o períodos, donde N es el mínimo del número de instantes o períodos que componen ambos valores.

Los operadores de comparación disponibles para los tipos de conjunto y de rango se dan a continuación. Recuerde que los rangos de enteros siempre se representan por su forma canónica.

- Comparaciones tradicionales

  `set {=, <>, <, >, <=, >=} set → boolean`

  `spans {=, <>, <, >, <=, >=} spans → boolean`

      SELECT intspan '[1,3]' = intspan '[1,4)';
      -- true
      SELECT floatspanset '{[1, 2),[2,3)}' = floatspanset '{[1,3)}';
      -- true
      SELECT tstzset '{2001-01-01, 2001-01-04}' <> tstzset '{2001-01-01, 2001-01-05}';
      -- false
      SELECT tstzspan '[2001-01-01, 2001-01-04)' <> tstzspan '[2001-01-03, 2001-01-05)';
      -- true
      SELECT floatspan '[3, 4]' < floatspan '(3, 4]';
      -- true
      SELECT intspanset '{[1,2],[3,4]}' < intspanset '{[3, 4]}';
      -- true
      SELECT floatspan '[3, 4]' > floatspan '[3, 4)';
      -- true
      SELECT tstzspan '[2001-01-03, 2001-01-04)' > tstzspan '[2001-01-02, 2001-01-05)';
      -- true
      SELECT floatspanset '{[1, 4)}' <= floatspanset '{[1, 5), [6, 7)}';
      -- true
      SELECT tstzspanset '{[2001-01-01, 2001-01-04)}' <=
        tstzspanset '{[2001-01-01, 2001-01-05), [2001-01-06, 2001-01-07)}';
      -- true
      SELECT tstzspan '[2001-01-03, 2001-01-05)' >= tstzspan '[2001-01-03, 2001-01-04)';
      -- true
      SELECT intspanset '{[1, 4)}' >= intspanset '{[1, 5), [6, 7)}';
      -- false

## Agregaciones

Hay varias funciones agregadas definidas para los tipos de conjunto y de rango. Estas se describen a continuación.

- La función `extent` devuelve el rango o período delimitador que engloba un conjunto de valores de rango o de tiempo.

- La unión es una operación muy útil para los tipos de conjunto y de rango. Como hemos visto en la setspan_set_ops, podemos calcular la unión de dos valores de conjunto o de rango usando el operador `+`. Sin embargo, también es muy útil tener una versión agregada del operador de unión para combinar un número arbitrario de valores. Las funciones `set_union` y `span_union` se pueden utilizar para este propósito.

- La función `tCount` generaliza la función de agregación tradicional `count`. El conteo temporal se puede utilizar para calcular en cada momento el número de objetos disponibles (por ejemplo, el número of períodos). La función `tCount` devuelve un entero temporal (ver el ttype_aggregation). La función tiene dos parámetros opcionales que especifican la granularidad (un `interval`) y el origen del tiempo (un `timestamptz`). Cuando se dan estos parámetros, el conteo temporal se calcula en rangos de tiempo de la granularidad dada (ver ttype_tiling)

- Rango o período delimitador

  `extent({set,spans}) → span`

      WITH spans(r) AS (
        SELECT floatspan '[1, 4)' UNION SELECT floatspan '(5, 8)' UNION
        SELECT floatspan '(7, 9)' )
      SELECT extent(r) FROM spans;
      -- [1,9)
      WITH times(ts) AS (
        SELECT tstzset '{2001-01-01, 2001-01-03, 2001-01-05}' UNION
        SELECT tstzset '{2001-01-02, 2001-01-04, 2001-01-06}' UNION
        SELECT tstzset '{2001-01-01, 2001-01-02}' )
      SELECT extent(ts) FROM times;
      -- [2001-01-01, 2001-01-06]
      WITH periods(ps) AS (
        SELECT tstzspanset '{[2001-01-01, 2001-01-02], [2001-01-03, 2001-01-04]}' UNION
        SELECT tstzspanset '{[2001-01-01, 2001-01-04], [2001-01-05, 2001-01-06]}' UNION
        SELECT tstzspanset '{[2001-01-02, 2001-01-06]}' )
      SELECT extent(ps) FROM periods;
      -- [2001-01-01, 2001-01-06]

- Unión agregada

  `setUnion({value,set}) → set`

  `spanUnion(spans) → spanset`

      WITH times(ts) AS (
        SELECT tstzset '{2001-01-01, 2001-01-03, 2001-01-05}' UNION
        SELECT tstzset '{2001-01-02, 2001-01-04, 2001-01-06}' UNION
        SELECT tstzset '{2001-01-01, 2001-01-02}' )
      SELECT setUnion(ts) FROM times;
      -- {2001-01-01, 2001-01-02, 2001-01-03, 2001-01-04, 2001-01-05, 2001-01-06}
      WITH periods(ps) AS (
        SELECT tstzspanset '{[2001-01-01, 2001-01-02], [2001-01-03, 2001-01-04]}' UNION
        SELECT tstzspanset '{[2001-01-02, 2001-01-03], [2001-01-05, 2001-01-06]}' UNION
        SELECT tstzspanset '{[2001-01-07, 2001-01-08]}' )
      SELECT spanUnion(ps) FROM periods;
      -- {[2001-01-01, 2001-01-04], [2001-01-05, 2001-01-06], [2001-01-07, 2001-01-08]}

- Conteo temporal

  `tCount(times) → {tintSeq,tintSeqSet}`

      WITH times(ts) AS (
        SELECT tstzset '{2001-01-01, 2001-01-03, 2001-01-05}' UNION
        SELECT tstzset '{2001-01-02, 2001-01-04, 2001-01-06}' UNION
        SELECT tstzset '{2001-01-01, 2001-01-02}' )
      SELECT tCount(ts) FROM times;
      -- {2@2001-01-01, 2@2001-01-02, 1@2001-01-03, 1@2001-01-04, 1@2001-01-05, 1@2001-01-06}
      WITH periods(ps) AS (
        SELECT tstzspanset '{[2001-01-01, 2001-01-02), [2001-01-03, 2001-01-04)}' UNION
        SELECT tstzspanset '{[2001-01-01, 2001-01-04), [2001-01-05, 2001-01-06)}' UNION
        SELECT tstzspanset '{[2001-01-02, 2001-01-06)}' )
      SELECT tCount(ps) FROM periods;
      -- {[2@2001-01-01, 3@2001-01-03, 1@2001-01-04, 2@2001-01-05, 2@2001-01-06)}

## Indexación

Se pueden crear índices GiST y SP-GiST en columnas de tablas de los tipos de conjunto y de rango. El índice GiST implementa un árbol R, mientras que el índice SP-GiST implementa un árbol cuádruple. Un ejemplo de creación de un índice GiST en una columna `During` de tipo `tstzspan` en una tabla `Reservation` es como sigue:

    CREATE TABLE Reservation (ReservationID integer PRIMARY KEY, RoomID integer,
      During tstzspan);
    CREATE INDEX Reservation_During_Idx ON Reservation USING GIST(During);

Un índice GiST o SP-GiST puede acelerar las consultas que involucran a los siguientes operadores: `=`, `&&`, `<@`, `@>`, `-|-`, `<<`, `>>`, `&<`, `&>`, `<<#`, `#>>`, `&<#`, `#&>` y `<->`.

Además, se pueden crear índices de árbol B para columnas de tabla de un tipo de rango o de tiempo. Para estos tipos de índices, básicamente la única operación útil es la igualdad. Hay un orden de clasificación de árbol B definido para valores de tipos de rango o de tiempo con los correspondientes operadores `<`, `<=`, `>` y `>=`, pero el orden es bastante arbitrario y no suele ser útil en el mundo real. El soporte del árbol B está destinado principalmente a permitir la clasificación interna en las consultas, en lugar de la creación de índices reales.

Finalmente, se pueden crear índices hash para columnas de tabla de un tipo de rango o de tiempo. Para estos tipos de índices, la única operación definida es la igualdad.