# Tipos temporales (Parte 2)

## Modificaciones

A continuación, explicamos la semántica de las operaciones de modificación (es decir, `insert`, `update` y `delete`) para tipos temporales. Estas operaciones tienen una semántica similar a las operaciones correspondientes para tablas temporales de tiempo de aplicación (application-time temporal tables) introducidas en el estándar SQL:2011. La principal diferencia es que SQL usa marcas de tiempo de tuplas (donde las marcas de tiempo se adjuntan a las tuplas), mientras que los valores temporales en MobilityDB usan marcas de tiempo de atributos (donde las marcas de tiempo se adjuntan a los valores de los atributos). Please refer to this article for a detailed discussion about tuple versus attribute timestamping in temporal databases.

La operación `insert` agrega a un valor temporal los instantes de otro sin modificar los instantes existentes, como se ilustra en la insert_fig.

### Operación de inserción para valores temporales.

Como se muestra en la figura, los valores temporales solo pueden intersectarse en su límite y, en ese caso, deben tener el mismo valor de base en sus marcas de tiempo comunes; de lo contrario, se genera un error. El resultado de la operación es la unión de los instantes para ambos valores temporales, como se muestra en el primer resultado de la figura. Esto es equivalente a una operación `merge` que se explica a continuación. Alternativamente, como se muestra en el segundo resultado de la figura, los fragmentos insertados que son disjuntos con el valor original se conectan al último instante anterior y al primer instante posterior al fragmento. Se utiliza un parámetro booleano `connect` para elegir entre los dos resultados, y el parámetro es verdadero por defecto. Nótese que esto solo se aplica a valores temporales continuos.

La operación `update` reemplaza los instantes en un primer valor temporal con los de un segundo valor como se ilustra en la update_delete_fig.

### Operaciones de actualización y supresión para valores temporales.

Como se muestra en la figura, el valor resultante contiene los instantes del segundo valor, independientemente de los instantes anteriores que tenía en el valor temporal original. Como en el caso de una operación `insert`, un parámetro booleano adicional determina si los nuevos fragmentos desconectados están conectados en el valor resultante, como se muestra en los dos posibles resultados de la figura. Cuando los dos valores temporales son disjuntos o solo se intersectan en su límite, esto corresponde a una operación `insert` como se explicó anteriormente. En este caso, la operación `update` se comporta como una operación `upsert` en SQL.

La operación `deleteTime` elimina los instantes de un valor temporal que intersectan un valor de tiempo. Esta operación se puede utilizar en dos situaciones diferentes, ilustradas en la update_delete_fig.

1. En el primer caso, que se muestra como el resultado superior de la figura, el significado de la operación es introducir brechas de tiempo después de eliminar los instantes del valor temporal que intersectan el valor de tiempo. Esto es equivalente a las operaciones de restricción (ttype_restrictions), que restringen un valor temporal al complemento del valor de tiempo.

2. El segundo caso, que se muestra como el resultado inferior de la figura, se usa para eliminar valores erróneos (por ejemplo, detectados como valores atípicos) sin introducir una brecha de tiempo, o para eliminar una brecha de tiempo. En este caso, los valores en el fragmento del valor temporal se eliminan y el último instante anterior y el primer instante posterior a une fragmento suprimido se conectan. Este comportamiento se especifica estableciendo un parámetro booleano adicional de la operación. Nótese que esto solo se aplica a valores temporales continuos.

La modif_sql_fig muestra las operaciones de modificación equivalentes para tablas temporales en el estándar SQL. Intuitivamente, estas figuras se obtienen girando 90 grados en el sentido de las agujas del reloj las figuras correspondientes para los valores temporales (insert_fig y update_delete_fig). Esto se debe al hecho de que en SQL, las tuplas consecutivas ordenadas por tiempo generalmente se conectan a través de las funciones de ventana `LEAD` y `LAG`.

### Operaciones de modificación para tablas temporales en SQL.

- Insertar un valor temporal en otro

  `insert(ttype,ttype,connect=true) → ttype`

      SELECT insert(tint '{1@2001-01-01, 3@2001-01-03, 5@2001-01-05}',
        tint '{3@2001-01-03, 7@2001-01-07}');
      -- {1@2001-01-01, 3@2001-01-03, 5@2001-01-05, 7@2001-01-07}
      SELECT insert(tint '{1@2001-01-01, 3@2001-01-03, 5@2001-01-05}',
        tint '{5@2001-01-03, 7@2001-01-07}');
      -- ERROR: The temporal values have different value at their overlapping instant 2001-01-03
      SELECT insert(tfloat '[1@2001-01-01, 2@2001-01-02]',
        tfloat '[1@2001-01-03, 1@2001-01-05]');
      -- [1@2001-01-01, 2@2001-01-02, 1@2001-01-03, 1@2001-01-05]
      SELECT insert(tfloat '[1@2001-01-01, 2@2001-01-02]',
        tfloat '[1@2001-01-03, 1@2001-01-05]', false);
      -- {[1@2001-01-01, 2@2001-01-02], [1@2001-01-03, 1@2001-01-05]}
      SELECT asText(insert(tgeompoint '{[Point(1 1 1)@2001-01-01, Point(2 2 2)@2001-01-02],
        [Point(3 3 3)@2001-01-04],[Point(1 1 1)@2001-01-05]}',
        tgeompoint 'Point(1 1 1)@2001-01-03'));
      /* {[POINT Z (1 1 1)@2001-01-01, POINT Z (2 2 2)@2001-01-02, POINT Z (1 1 1)@2001-01-03,
       POINT Z (3 3 3)@2001-01-04], [POINT Z (1 1 1)@2001-01-05]} */

- Actualizar un valor temporal con otro

  `update(ttype,ttype,connect=true) → ttype`

      SELECT update(tint '{1@2001-01-01, 3@2001-01-03, 5@2001-01-05}',
        tint '{5@2001-01-03, 7@2001-01-07}');
      -- {1@2001-01-01, 5@2001-01-03, 5@2001-01-05, 7@2001-01-07}
      SELECT update(tfloat '[1@2001-01-01, 1@2001-01-05]',
        tfloat '[1@2001-01-02, 3@2001-01-03, 1@2001-01-04]');
      -- {[1@2001-01-01, 1@2001-01-02, 3@2001-01-03, 1@2001-01-04, 1@2001-01-05]}
      SELECT asText(update(tgeompoint '{[Point(1 1 1)@2001-01-01, Point(3 3 3)@2001-01-03,
        Point(1 1 1)@2001-01-05], [Point(1 1 1)@2001-01-07]}',
        tgeompoint '[Point(2 2 2)@2001-01-02, Point(2 2 2)@2001-01-04]'));
      /*  {[POINT Z (1 1 1)@2001-01-01, POINT Z (2 2 2)@2001-01-02, POINT Z (2 2 2)@2001-01-04,
        POINT Z (1 1 1)@2001-01-05], [POINT Z (1 1 1)@2001-01-07]} */
      SELECT asText(update(
        tgeometry '[Point(1 1)@2001-01-01, Point(3 3)@2001-01-03, Point(1 1)@2001-01-05]',
        tgeometry '[Linestring(2 2,3 3)@2001-01-02, Linestring(3 3,2 2)@2001-01-04]'));
      /* [POINT(1 1)@2001-01-01, LINESTRING(2 2,3 3)@2001-01-02,
          LINESTRING(3 3,2 2)@2001-01-04], (POINT(3 3)@2001-01-04, POINT(1 1)@2001-01-05] */

- Eliminar de un valor temporal un valor de tiempo

  `deleteTime(ttype,time,connect=true) → ttype`

      SELECT deleteTime(tint '[1@2001-01-01, 1@2001-01-03]', timestamptz '2001-01-02', false);
      -- {[1@2001-01-01, 1@2001-01-02), (1@2001-01-02, 1@2001-01-03]}
      SELECT deleteTime(tint '[1@2001-01-01, 1@2001-01-03]', timestamptz '2001-01-02');
      -- [1@2001-01-01, 1@2001-01-03]
      SELECT deleteTime(tfloat '[1@2001-01-01, 4@2001-01-02, 2@2001-01-04, 5@2001-01-05]',
        tstzspan '[2001-01-02, 2001-01-04]');
      -- [1@2001-01-01, 5@2001-01-05]
      SELECT asText(deleteTime(tgeompoint '{[Point(1 1 1)@2001-01-01,
        Point(2 2 2)@2001-01-02], [Point(3 3 3)@2001-01-04, Point(3 3 3)@2001-01-05]}',
        tstzspan '[2001-01-02, 2001-01-04]'));
      /* {[POINT Z (1 1 1)@2001-01-01, POINT Z (2 2 2)@2001-01-02, POINT Z (3 3 3)@2001-01-04,
        POINT Z (3 3 3)@2001-01-05]} */

- Anexar un instante temporal a un valor temporal

  `appendInstant(ttype,ttypeInst,interp=NULL) → ttype`

  `appendInstant(ttypeInst,interp=NULL,maxdist=NULL,maxt=NULL) → ttypeSeq`

  La primera versión de la función devuelve el resultado de agregar el segundo argumento al primero. Si cualquiera de las entradas es NULL, se devuelve NULL.

  La segunda versión de la función anterior es una función de agregación que devuelve el resultado de agregar sucesivamente un conjunto de filas de valores temporales. Esto significa que funciona de la misma manera que las funciones `SUM()` y `AVG()` y, como la mayoría de los agregados, también ignora los valores NULL. Dos argumentos opcionales establecen una distancia máxima y un intervalo de tiempo máximo de modo que se introduce una brecha de tiempo cada vez que dos instantes consecutivos tienen una distancia o un intervalo de tiempo mayor que estos valores. Para puntos temporales, la distancia se especifica en unidades del sistema de coordenadas. Si uno de estos argumentos no se dan, no se tiene en cuenta para determinar las brechas.

      SELECT appendInstant(tint '1@2001-01-01', tint '1@2001-01-02');
      -- [1@2001-01-01, 1@2001-01-02]
      SELECT appendInstant(tint '1@2001-01-01', tint '1@2001-01-02', 'discrete');
      -- {1@2001-01-01, 1@2001-01-02}
      SELECT appendInstant(tint '[1@2001-01-01]', tint '1@2001-01-02');
      -- [1@2001-01-01, 1@2001-01-02]
      SELECT asText(appendInstant(tgeompoint '{[Point(1 1 1)@2001-01-01,
        Point(2 2 2)@2001-01-02], [Point(3 3 3)@2001-01-04, Point(3 3 3)@2001-01-05]}',
        tgeompoint 'Point(1 1 1)@2001-01-06'));
      /* {[POINT Z (1 1 1)@2001-01-01, POINT Z (2 2 2)@2001-01-02],
         [POINT Z (3 3 3)@2001-01-04, POINT Z (3 3 3)@2001-01-05,
         POINT Z (1 1 1)@2001-01-06]} */
      SELECT asText(appendInstant(tgeometry '{[Point(1 1)@2001-01-01, Point(2 2)@2001-01-02],
        [Linestring(2 2,3 3)@2001-01-04, Point(3 3)@2001-01-05]}',
        tgeometry 'Linestring(1 1,2 2)@2001-01-06'));
      /* {[POINT(1 1)@2001-01-01, POINT(2 2)@2001-01-02], [LINESTRING(2 2,3 3)@2001-01-04,
           POINT(3 3)@2001-01-05, LINESTRING(1 1,2 2)@2001-01-06]} */

      WITH temp(inst) AS (
        SELECT tfloat '1@2001-01-01' UNION SELECT tfloat '2@2001-01-02' UNION
        SELECT tfloat '3@2001-01-03' UNION SELECT tfloat '4@2001-01-04' UNION
        SELECT tfloat '5@2001-01-05' )
      SELECT appendInstant(inst ORDER BY inst) FROM temp;
      -- [1@2001-01-01, 5@2001-01-05]
      WITH temp(inst) AS (
        SELECT tfloat '1@2001-01-01' UNION SELECT tfloat '2@2001-01-02' UNION
        SELECT tfloat '3@2001-01-03' UNION SELECT tfloat '4@2001-01-04' UNION
        SELECT tfloat '5@2001-01-05' )
      SELECT appendInstant(inst, 'discrete' ORDER BY inst) FROM temp;
      -- {1@2001-01-01, 2@2001-01-02, 3@2001-01-03, 4@2001-01-04, 5@2001-01-05}
      WITH temp(inst) AS (
        SELECT tgeogpoint 'Point(1 1)@2001-01-01' UNION
        SELECT tgeogpoint 'Point(2 2)@2001-01-02' UNION
        SELECT tgeogpoint 'Point(3 3)@2001-01-03' UNION
        SELECT tgeogpoint 'Point(4 4)@2001-01-04' UNION
        SELECT tgeogpoint 'Point(5 5)@2001-01-05' )
      SELECT asText(appendInstant(inst ORDER BY inst)) FROM temp;
      /* [POINT(1 1)@2001-01-01, POINT(2 2)@2001-01-02, POINT(3 3)@2001-01-03,
         POINT(4 4)@2001-01-04, POINT(5 5)@2001-01-05] */

  Observe que en la primera consulta con `tfloat`, las observaciones intermedias fueron eliminadas por el proceso de normalización ya que eran redundantes debido a la interpolación lineal. Este no es el caso de la segunda consulta con interpolación discreta o la tercera consulta con `tgeogpoint`, donde se utilizan coordenadas geodésicas.

      WITH temp(inst) AS (
        SELECT tfloat '1@2001-01-01' UNION SELECT tfloat '2@2001-01-02' UNION
        SELECT tfloat '4@2001-01-04' UNION SELECT tfloat '5@2001-01-05' UNION
        SELECT tfloat '7@2001-01-07' )
      SELECT appendInstant(inst, NULL, 0.0, '1 day' ORDER BY inst) FROM temp;
      -- {[1@2001-01-01, 2@2001-01-02], [4@2001-01-04, 5@2001-01-05], [7@2001-01-07]}
      WITH temp(inst) AS (
        SELECT tgeompoint 'Point(1 1)@2001-01-01' UNION
        SELECT tgeompoint 'Point(2 2)@2001-01-02' UNION
        SELECT tgeompoint 'Point(4 4)@2001-01-04' UNION
        SELECT tgeompoint 'Point(5 5)@2001-01-05' UNION
        SELECT tgeompoint 'Point(7 7)@2001-01-07' )
      SELECT asText(appendInstant(inst, NULL, sqrt(2), '1 day' ORDER BY inst)) FROM temp;
      /* {[POINT(1 1)@2001-01-01, POINT(2 2)@2001-01-02],
         [POINT(4 4)@2001-01-04, POINT(5 5)@2001-01-05], [POINT(7 7)@2001-01-07]} */

- Anexar una secuencia temporal a un valor temporal

  `appendSequence(ttype,ttypeSeq) → {ttypeSeq, ttypeSeqSet}`

  `appendSequence(ttypeSeq) → {ttypeSeq,ttypeSeqSet}`

  La primera versión de la función devuelve el resultado de agregar el segundo argumento al primero. Si cualquiera de las entradas es NULL, se devuelve NULL.

  La segunda versión de la función anterior es una función de agregación que devuelve el resultado de agregar sucesivamente un conjunto de filas de valores temporales. Esto significa que funciona de la misma manera que las funciones `SUM()` y `AVG()` y, como la mayoría de los agregados, también ignora los valores NULL.

      SELECT appendSequence(tint '1@2001-01-01', tint '{2@2001-01-02, 3@2001-01-03}');
      -- {1@2001-01-01, 2@2001-01-02, 3@2001-01-03}
      SELECT appendSequence(tint '[1@2001-01-01, 2@2001-01-02]',
        tint '[2@2001-01-02, 3@2001-01-03]');
      -- [1@2001-01-01, 2@2001-01-02, 3@2001-01-03]
      SELECT asText(appendSequence(tgeompoint '{[Point(1 1 1)@2001-01-01,
        Point(2 2 2)@2001-01-02], [Point(3 3 3)@2001-01-04, Point(3 3 3)@2001-01-05]}',
        tgeompoint '[Point(3 3 3)@2001-01-05, Point(1 1 1)@2001-01-06]'));
      /* {[POINT Z (1 1 1)@2001-01-01, POINT Z (2 2 2)@2001-01-02],
         [POINT Z (3 3 3)@2001-01-04, POINT Z (3 3 3)@2001-01-05,
         POINT Z (1 1 1)@2001-01-06]} */
      SELECT asText(appendSequence(tgeometry '{[Point(1 1)@2001-01-01, Point(2 2)@2001-01-02],
        [Linestring(3 3,2 2)@2001-01-04, Point(3 3)@2001-01-05]}',
        tgeometry '[Point(3 3)@2001-01-05, Linestring(3 3,1 1)@2001-01-06]'));
      /* {[POINT(1 1)@2001-01-01, POINT(2 2)@2001-01-02], [LINESTRING(3 3,2 2)@2001-01-04,
           POINT(3 3)@2001-01-05, LINESTRING(3 3,1 1)@2001-01-06]} */

- Fusionar los valores temporales

  `merge(ttype,ttype) → ttype`

  `merge(ttype[]) → ttype`

  `merge(ttype) → ttype`

  Los valores temporales solo pueden intersectar en su límite. En ese caso, para todos los tipos temporales excepto `tgeometry` y `tgeography`, sus valores de base en las marcas de tiempo comunes deben ser los mismos, de lo contrario se genera un error. Para los tipos `tgeometry` y `tgeography`, si el valor en sus marcas de tiempo comunes es diferente, el valor resultante después de la `merge` será la unión espacial de los valores. La razón de un comportamiento diferente para estos tipos es que son los únicos tipos temporales que no son tipos escalares, es decir, su valor en una marca de tiempo dada no es un único elemento del dominio del tipo base, sino más bien un subconjunto de su dominio.

  La tercera versión de la función anterior es una función de agregación que devuelve el resultado de agregar sucesivamente un conjunto de filas de valores temporales. Esto significa que funciona de la misma manera que las funciones `SUM()` y `AVG()` y, como la mayoría de los agregados, también ignora los valores NULL.

      SELECT merge(tint '1@2001-01-01', tint '1@2001-01-02');
      -- {1@2001-01-01, 1@2001-01-02}
      SELECT merge(tint '[1@2001-01-01, 2@2001-01-02]', tint '[2@2001-01-02, 1@2001-01-03]');
      -- [1@2001-01-01, 2@2001-01-02, 1@2001-01-03]
      SELECT merge(tint '[1@2001-01-01, 2@2001-01-02]', tint '[3@2001-01-03, 1@2001-01-04]');
      -- {[1@2001-01-01, 2@2001-01-02], [3@2001-01-03, 1@2001-01-04]}
      SELECT merge(tint '[1@2001-01-01, 2@2001-01-02]', tint '[1@2001-01-02, 2@2001-01-03]');
      -- ERROR:  The temporal values have different value at their common timestamp 2001-01-02
      SELECT asText(merge(tgeompoint '{[Point(1 1 1)@2001-01-01,
        Point(2 2 2)@2001-01-02], [Point(3 3 3)@2001-01-04, Point(3 3 3)@2001-01-05]}',
        tgeompoint '{[Point(3 3 3)@2001-01-05, Point(1 1 1)@2001-01-06]}'));
      /* {[POINT Z (1 1 1)@2001-01-01, POINT Z (2 2 2)@2001-01-02],
         [POINT Z (3 3 3)@2001-01-04, POINT Z (3 3 3)@2001-01-05,
         POINT Z (1 1 1)@2001-01-06]} */
      SELECT asText(merge(tgeometry 'Linestring(1 1,5 1)@2001-01-01',
        tgeometry '{Linestring(5 1,10 1)@2001-01-01, Point(3 3)@2001-01-02}'));
      -- {LINESTRING(1 1,5 1,10 1)@2001-01-01, POINT(3 3)@2001-01-02}

      SELECT merge(ARRAY[tint '1@2001-01-01', '1@2001-01-02']);
      -- {1@2001-01-01, 1@2001-01-02}
      SELECT merge(ARRAY[tint '{1@2001-01-01, 2@2001-01-02}', '{2@2001-01-02, 3@2001-01-03}']);
      -- {1@2001-01-01, 2@2001-01-02, 3@2001-01-03}
      SELECT merge(ARRAY[tint '{1@2001-01-01, 2@2001-01-02}', '{3@2001-01-03, 4@2001-01-04}']);
      -- {1@2001-01-01, 2@2001-01-02, 3@2001-01-03, 4@2001-01-04}
      SELECT merge(ARRAY[tint '[1@2001-01-01, 2@2001-01-02]', '[2@2001-01-02, 1@2001-01-03]']);
      -- [1@2001-01-01, 2@2001-01-02, 1@2001-01-03]
      SELECT merge(ARRAY[tint '[1@2001-01-01, 2@2001-01-02]', '[3@2001-01-03, 4@2001-01-04]']);
      -- {[1@2001-01-01, 2@2001-01-02], [3@2001-01-03, 4@2001-01-04]}
      SELECT asText(merge(ARRAY[tgeompoint '{[Point(1 1)@2001-01-01, Point(2 2)@2001-01-02],
        [Point(3 3)@2001-01-03, Point(4 4)@2001-01-04]}', '{[Point(4 4)@2001-01-04,
        Point(3 3)@2001-01-05], [Point(6 6)@2001-01-06, Point(7 7)@2001-01-07]}']));
      /* {[Point(1 1)@2001-01-01, Point(2 2)@2001-01-02], [Point(3 3)@2001-01-03,
         Point(4 4)@2001-01-04, Point(3 3)@2001-01-05],
         [Point(6 6)@2001-01-06, Point(7 7)@2001-01-07]} */
      SELECT asText(merge(ARRAY[tgeompoint '{[Point(1 1)@2001-01-01, Point(2 2)@2001-01-02]}',
        '{[Point(2 2)@2001-01-02, Point(1 1)@2001-01-03]}']));
      -- [Point(1 1)@2001-01-01, Point(2 2)@2001-01-02, Point(1 1)@2001-01-03]
      SELECT asText(merge(ARRAY[tgeometry '{[Point(1 1)@2001-01-01, Point(2 2)@2001-01-02]}',
        '{[Linestring(2 2,1 1)@2001-01-02, Point(1 1)@2001-01-03]}']));
      -- {[POINT(1 1)@2001-01-01, LINESTRING(2 2,1 1)@2001-01-02, POINT(1 1)@2001-01-03]}

      WITH temp(inst) AS (
      SELECT tfloat '1@2001-01-01' UNION SELECT tfloat '2@2001-01-02' UNION
      SELECT tfloat '3@2001-01-03' UNION SELECT tfloat '4@2001-01-04' UNION
      SELECT tfloat '5@2001-01-05' )
      SELECT merge(inst) FROM temp;
      -- {1@2001-01-01, 2@2001-01-02, 3@2001-01-03, 4@2001-01-04, 5@2001-01-05}

## Restricciones

Hay dos conjuntos complementarios de funciones de restricción. El primer conjunto de funciones restringe el valor temporal con respecto a un valor o una extensión de tiempo. Dos ejemplos son `atValues` o `atTime`. El segundo conjunto de funciones restringe el valor temporal con respecto al complement de un valor o una extensión de tiempo. Dos ejemplos son `minusValues` o `minusTime`

- Restringir a (al complemento de) un valor

  `atValues(ttype,values) → ttype`

  `minusValues(ttype,values) → ttype`

      SELECT atValues(tint '[1@2001-01-01, 1@2001-01-15)', 1);
      -- [1@2001-01-01, 1@2001-01-15)
      SELECT atValues(tfloat '[1@2001-01-01, 4@2001-01-4)', floatset '{1, 3, 5}');
      -- {[1@2001-01-01], [3@2001-01-03]}
      SELECT atValues(tfloat '[1@2001-01-01, 4@2001-01-4)', floatspan '[1,3]');
      -- [1@2001-01-01, 3@2001-01-03]
      SELECT atValues(tfloat '[1@2001-01-01, 5@2001-01-05)',
        floatspanset '{[1,2], [3,4]}');
      -- {[1@2001-01-01, 2@2001-01-02],[3@2001-01-03, 4@2001-01-04]}
      SELECT asText(atValues(tgeompoint '[Point(0 0 0)@2001-01-01, Point(2 2 2)@2001-01-03)',
        geometry 'Point(1 1 1)'));
      -- {[POINT Z (1 1 1)@2001-01-02]}
      SELECT asText(atValues(tgeompoint '[Point(0 0)@2001-01-01, Point(2 2)@2001-01-03)',
        geomset '{"Point(0 0)", "Point(1 1)"}'));
      -- {[POINT(0 0)@2001-01-01], [POINT(1 1)@2001-01-02]}
      SELECT asText(atValues(tgeometry '[Point(0 0)@2001-01-01, Linestring(0 0,2 2)@2001-01-02,
        Linestring(0 0,2 2)@2001-01-03]', geometry 'Linestring(0 0,2 2)'));
      -- {[LINESTRING(0 0,2 2)@2001-01-02, LINESTRING(0 0,2 2)@2001-01-03]}

      SELECT minusValues(tint '[1@2001-01-01, 2@2001-01-02, 2@2001-01-03)', 1);
      -- {[2@2001-01-02, 2@2001-01-03)}
      SELECT minusValues(tfloat '[1@2001-01-01, 4@2001-01-4)', floatset '{2, 3}');
      /* {[1@2001-01-01, 2@2001-01-02), (2@2001-01-02, 3@2001-01-03),
         (3@2001-01-03, 4@2001-01-04)} */
      SELECT minusValues(tfloat '[1@2001-01-01, 4@2001-01-4)', floatspan '[2,3]');
      -- {[1@2001-01-01, 2@2001-01-02), (3@2001-01-03, 4@2001-01-04)}
      SELECT minusValues(tfloat '[1@2001-01-01, 5@2001-01-05)',
        floatspanset '{[1,2], [3,4]}');
      -- {(2@2001-01-02, 3@2001-01-03), (4@2001-01-04, 5@2001-01-05)}
      SELECT asText(minusValues(tgeompoint '[Point(0 0 0)@2001-01-01, Point(2 2 2)@2001-01-03)',
        geometry 'Point(1 1 1)'));
      /* {[POINT Z (0 0 0)@2001-01-01, POINT Z (1 1 1)@2001-01-02),
         (POINT Z (1 1 1)@2001-01-02, POINT Z (2 2 2)@2001-01-03)} */
      SELECT asText(minusValues(tgeompoint '[Point(0 0 0)@2001-01-01, Point(3 3 3)@2001-01-04)',
        geomset '{"Point(1 1 1)', 'Point(2 2 2)"}'));
      /* {[POINT Z (0 0 0)@2001-01-01, POINT Z (1 1 1)@2001-01-02),
         (POINT Z (1 1 1)@2001-01-02, POINT Z (2 2 2)@2001-01-03),
        (POINT Z (2 2 2)@2001-01-03, POINT Z (3 3 3)@2001-01-04)} */
      SELECT asText(minusValues(tgeometry '[Point(0 0)@2001-01-01, Linestring(0 0,2 2)@2001-01-02,
        Linestring(0 0,2 2)@2001-01-03]', geometry 'Linestring(0 0,2 2)'));
      --  {[POINT(0 0)@2001-01-01, POINT(0 0)@2001-01-02)}

- Restringir a (al complemento de) un valor de tiempo

  `atTime(ttype,times) → ttype`

  `minusTime(ttype,times) → ttype`

      SELECT atTime(tfloat '[1@2001-01-01, 5@2001-01-05)', timestamptz '2001-01-02');
      -- 2@2001-01-02
      SELECT atTime(tint '[1@2001-01-01, 1@2001-01-15)',
        tstzset '{2001-01-01, 2001-01-03}');
      -- {1@2001-01-01, 1@2001-01-03}
      SELECT atTime(tfloat '{[1@2001-01-01, 3@2001-01-03), [3@2001-01-04, 1@2001-01-06)}',
        tstzspan '[2001-01-02,2001-01-05)');
      -- {[2@2001-01-02, 3@2001-01-03), [3@2001-01-04, 2@2001-01-05)}
      SELECT atTime(tint '[1@2001-01-01, 1@2001-01-15)',
        tstzspanset '{[2001-01-01, 2001-01-03), [2001-01-04, 2001-01-05)}');
      -- {[1@2001-01-01, 1@2001-01-03),[1@2001-01-04, 1@2001-01-05)}

      SELECT minusTime(tfloat '[1@2001-01-01, 5@2001-01-05)', timestamptz '2001-01-02');
      -- {[1@2001-01-01, 2@2001-01-02), (2@2001-01-02, 5@2001-01-05)}
      SELECT minusTime(tint '[1@2001-01-01, 1@2001-01-15)',
        tstzset '{2001-01-02, 2001-01-03}');
      /* {[1@2001-01-01, 1@2001-01-02), (1@2001-01-02, 1@2001-01-03),
         (1@2001-01-03, 1@2001-01-15)} */
      SELECT minusTime(tfloat '{[1@2001-01-01, 3@2001-01-03), [3@2001-01-04, 1@2001-01-06)}',
        tstzspan '[2001-01-02,2001-01-05)');
      -- {[1@2001-01-01, 2@2001-01-02), [2@2001-01-05, 1@2001-01-06)}
      SELECT minusTime(tint '[1@2001-01-01, 1@2001-01-15)',
        tstzspanset '{[2001-01-02, 2001-01-03), [2001-01-04, 2001-01-05)}');
      /* {[1@2001-01-01, 1@2001-01-02), [1@2001-01-03, 1@2001-01-04),
         [1@2001-01-05, 1@2001-01-15)} */

## Operadores de cuadro delimitador

Estos operadores determinan si los cuadros delimitadores de sus argumentos satisfacen el predicado y dan como resultado un valor booleano. Como se indica en el ttype_p1, el cuadro delimitador asociado a un tipo temporal depende del tipo base: es el tipo `tstzspan` para los tipos `tbool` y `ttext`, el tipo `tbox` para los tipos `tint` y `tfloat` y el tipo `stbox` para los tipos `tgeompoint` y `tgeogpoint`. Además, como se dijo en la box_conversions, muchos tipos PostgreSQL, PostGIS o MobilityDB se pueden convertir a los tipos `tbox` y `stbox`. Por ejemplo, los tipos numéricos y los rangos se pueden convertir al tipo `tbox`, los tipos `geometry` y `geography` se pueden convertir al tipo `stbox` y los tipos de tiempo y los tipos temporales se pueden convertir a los tipos `tbox` y `stbox`.

Un primer conjunto de operadores considera las relaciones topológicas entre los cuadros delimitadores. Hay cinco operadores topológicos: superposición (`&&`), contiene (`@>`), está contenido (`<@`), mismo (`~=`) y adyacente (`-|-`). Los argumentos de estos operadores pueden ser un tipo base, una cuadro delimitador o un tipo temporal y los operadores verifican la relación topológica teniendo en cuenta el valor y/o la dimensión temporal según el tipo de los argumentos.

Otro conjunto de operadores considera la posición relativa de los cuadros delimitadores. Los operadores `<<`, `>>`, `&<` y `&>` consideran la dimensión de valor para los tipos `tint` y `tfloat` y las coordenadas X para los tipos `tgeompoint` y `tgeogpoint`, los operadores `<<|`, `|>>`, `&<|` y `|&>` consideran las coordenadas Y para los tipos `tgeompoint` y `tgeogpoint`, los operadores `<</`, `/>>`, `&</` y `/&>` consideran las coordenadas Z para los tipos `tgeompoint` y `tgeogpoint` y los operadores `<<#`, `#>>`, `#&<` y `#&>` consideran la dimensión tiempo para todos los tipos temporales.

Finalmente, cabe destacar que los operadores de cuadro delimitador permiten mezclar geometrías 2D/3D pero en ese caso, el cálculo sólo se realiza en 2D.

Refiérase a la box_topo_pos para los operadores de cuadro delimitador.

## Comparaciones

### Comparaciones tradicionales

Los operadores de comparación tradicionales (`=`, `<`, etc.) requieren que los operandos izquierdo y derecho sean del mismo tipo base. Excepto la igualdad y la no igualdad, los otros operadores de comparación no son útiles en el mundo real pero permiten que los índices de árbol B se construyan sobre tipos temporales. Estos operadores comparan los períodos delimitadores (ver la setspan_comparisons), después los cuadros delimitadores (ver la box_comparisons) y si son iguales, entonces la comparación depende del subtipo. Para los valores de instante, primero comparan las marcas de tiempo y, si son iguales, comparan los valores. Para los valores de secuencia, comparan los primeros N instantes, donde N es el mínimo del número de instantes que componen ambos valores. Finalmente, para los valores de conjuntos de secuencias, comparan los primeros N valores de secuencia, donde N es el mínimo del número de secuencias que componen ambos valores.

Los operadores de igualdad y no igualdad consideran la representación equivalente para diferentes subtipos como se muestra a continuación.

    SELECT tint '1@2001-01-01' = tint '{1@2001-01-01}';
    -- true
    SELECT tfloat '1.5@2001-01-01' = tfloat '[1.5@2001-01-01]';
    -- true
    SELECT ttext 'AAA@2001-01-01' = ttext '{[AAA@2001-01-01]}';
    -- true
    SELECT tgeompoint '{Point(1 1)@2001-01-01, Point(2 2)@2001-01-02}' =
      tgeompoint '{[Point(1 1)@2001-01-01], [Point(2 2)@2001-01-02]}';
    -- true
    SELECT tgeogpoint '[Point(1 1 1)@2001-01-01, Point(2 2 2)@2001-01-02]' =
      tgeogpoint '{[Point(1 1 1)@2001-01-01], [Point(2 2 2)@2001-01-02]}';
    -- true

- Comparaciones tradicionales

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

      SELECT tint '[1@2001-01-01, 1@2001-01-04)' = tint '[2@2001-01-03, 2@2001-01-05)';
      -- false
      SELECT tint '[1@2001-01-01, 1@2001-01-04)' <> tint '[2@2001-01-03, 2@2001-01-05)';
      -- true
      SELECT tint '[1@2001-01-01, 1@2001-01-04)' < tint '[2@2001-01-03, 2@2001-01-05)';
      -- true
      SELECT tint '[1@2001-01-01, 1@2001-01-04)' > tint '[2@2001-01-03, 2@2001-01-05)';
      -- false
      SELECT tint '[1@2001-01-01, 1@2001-01-04)' <= tint '[2@2001-01-03, 2@2001-01-05)';
      -- true
      SELECT tint '[1@2001-01-01, 1@2001-01-04)' >= tint '[2@2001-01-03, 2@2001-01-05)';
      -- false

### Comparaciones alguna vez y siempre

Una posible generalización de los operadores de comparación tradicionales (`=`, `<>`, `<`, `<=`, etc.) a tipos temporales consiste en determinar si la comparación es alguna vez o siempre verdadera. En este caso, el resultado es un valor booleano. MobilityDB proporciona operadores para probar si la comparación de un valor temporal y un valor del tipo base or dos valores temporales es alguna vez o siempre verdadera. Estos operadores se indican anteponiendo los operadores de comparación tradicionales con, respectivamente, `?` (alguna vez) y `%` (siempre). Algunos ejemplos son `?=`, `%<>` o `?<=`. La igualdad y la no igualdad alguna vez o siempre están disponibles para todos los tipos temporales, mientras que las desigualdades alguna vez o siempre sólo están disponibles para los tipos temporales cuyo tipo base tiene un orden total definido, es decir, `tint`, `tfloat` o `ttext`. Las comparaciones alguna vez y siempre son operadores inversos: por ejemplo, `?=` es el inverso de `%<>` y `?>` es el inverso de `%<=`.

- Comparaciones alguna vez y siempre

  `{base,ttype} {?=, ?<>, ?<, ?>, ?<=, ?>=} {base,ttype} → boolean`

  `{base,ttype} {%=, %<>, %<, %>, %<=, %>=} {base,ttype} → boolean`

  Los operadores no tienen en cuenta si los límites son inclusivos o no.

      SELECT tint '[1@2001-01-01, 3@2001-01-04]' ?= 2;
      -- false
      SELECT tgeometry '[Point(0 0)@2001-01-01, Linestring(0 0,1 1)@2001-01-04]' ?=
        geometry 'Linestring(1 1,0 0)';
      -- true
      SELECT tfloat '[1@2001-01-01, 1@2001-01-04)' %= 1;
      -- true
      SELECT tgeometry '[Linestring(0 0,1 1)@2001-01-01, Linestring(1 1,0 0)@2001-01-04)' %=
        geometry 'Linestring(0 0,1 1)';
      -- true

      SELECT tfloat '[1@2001-01-01, 3@2001-01-04)' ?<> 2;
      -- true
      SELECT tgeompoint '[Point(1 1)@2001-01-01, Point(1 1)@2001-01-04)' ?<>
        geometry 'Point(1 1)';
      -- false
      SELECT tfloat '[1@2001-01-01, 3@2001-01-04)' %<> 2;
      -- false
      SELECT tgeogpoint '[Point(1 1)@2001-01-01, Point(1 1)@2001-01-04)' %<>
        geography 'Point(2 2)';
      -- true

      SELECT tint '[1@2001-01-01, 4@2001-01-04]' ?< 2;
      -- true
      SELECT tfloat '[1@2001-01-01, 4@2001-01-04)' %< 2;
      -- false

      SELECT tint '[1@2001-01-03, 1@2001-01-05]' ?> 0;
      -- true
      SELECT tfloat '[1@2001-01-03, 1@2001-01-05)' %> 1;
      -- false

      SELECT tint '[1@2001-01-01, 1@2001-01-05]' ?<= 2;
      -- true
      SELECT tfloat '[1@2001-01-01, 1@2001-01-05)' %<= 4;
      -- true

      SELECT ttext '{[AAA@2001-01-01, AAA@2001-01-03), [BBB@2001-01-04, BBB@2001-01-05)}'
         ?> 'AAA'::text;
      -- true
      SELECT ttext '{[AAA@2001-01-01, AAA@2001-01-03), [BBB@2001-01-04, BBB@2001-01-05)}'
         %> 'AAA'::text;
      -- false

### Comparaciones temporales

Otra posible generalización de los operadores de comparación tradicionales (`=`, `<>`, `<`, `<=`, etc.) a tipos temporales consiste en determinar si la comparación es verdadera o falsa en cada instante. En este caso, el resultado es un booleano temporal. Los operadores de comparación temporal se indican anteponiendo los operadores de comparación tradicionales con `#`. Algunos ejemplos son `#=` o `#<=`. La igualdad y no igualdad temporal están disponibles para todos los tipos temporales, mientras que las desigualdades temporales sólo están disponibles para los tipos temporales cuyo tipo base tiene un orden total definido, es decir, `tint`, `tfloat` o `ttext`.

- Comparaciones temporales

  `{base,ttype} {#=, #<>, #<, #>, #<=, #>=} {base,ttype} → boolean`

      SELECT tfloat '[1@2001-01-01, 2@2001-01-04)' #= 3;
      -- {[f@2001-01-01, f@2001-01-04)}
      SELECT tfloat '[1@2001-01-01, 4@2001-01-04)' #= tfloat '[4@2001-01-02, 1@2001-01-05)';
      -- {[f@2001-01-02, t@2001-01-03], (f@2001-01-03, f@2001-01-04)}
      SELECT tgeompoint '[Point(0 0)@2001-01-01, Point(2 2)@2001-01-03)' #=
        geometry 'Point(1 1)';
      -- {[f@2001-01-01, t@2001-01-02], (f@2001-01-02, f@2001-01-03)}
      SELECT tgeometry '[Point(0 0)@2001-01-01, Linestring(1 1,2 2)@2001-01-03]' #=
        geometry 'Linestring(2 2,1 1)';
      -- {[f@2001-01-01, t@2001-01-03]}

      SELECT tfloat '[1@2001-01-01, 4@2001-01-04)' #<> 2;
      -- {[t@2001-01-01, f@2001-01-02], (t@2001-01-02, 2001-01-04)}
      SELECT tfloat '[1@2001-01-01, 4@2001-01-04)' #<> tfloat '[2@2001-01-02, 2@2001-01-05)';
      -- {[f@2001-01-02], (t@2001-01-02, t@2001-01-04)}
      SELECT tgeometry '[Point(0 0)@2001-01-01, Linestring(1 1,2 2)@2001-01-03]' #<>
        geometry 'Linestring(2 2,1 1)';
      -- {[t@2001-01-01, f@2001-01-03]}

      SELECT tfloat '[1@2001-01-01, 4@2001-01-04)' #< 2;
      -- {[t@2001-01-01, f@2001-01-02, f@2001-01-04)}
      SELECT 1 #> tint '[1@2001-01-03, 1@2001-01-05)';
      -- [f@2001-01-03, f@2001-01-05)
      SELECT tfloat '[1@2001-01-01, 1@2001-01-05)' #<= tfloat '{2@2001-01-03, 3@2001-01-04}';
      -- {t@2001-01-03, t@2001-01-04}
      SELECT 'AAA'::text #> ttext '{[AAA@2001-01-01, AAA@2001-01-03),
        [BBB@2001-01-04, BBB@2001-01-05)}';
      -- {[f@2001-01-01, f@2001-01-03), [t@2001-01-04, t@2001-01-05)}

## Funciones de utilidad

- Versión de la extensión MobilityDB

  `mobilitydb_version() → text`

      SELECT mobilitydb_version();
      -- MobilityDB 1.3.0

- Versión de la extensión MobilityDB y de sus dependencias

  `mobilitydb_full_version() → text`

      /* MobilityDB 1.3.0, PostgreSQL 17.2, PostGIS 3.5.2, GEOS 3.12.0-CAPI-1.18.0, PROJ 9.2.0,
         JSON-C 0.13.1, GSL 2.5 */