Tabla de contenidos
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).
La operación insert
agrega a un valor temporal los instantes de otro sin modificar los instantes existentes, como se ilustra en Figura 6.1, “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 Figura 6.2, “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 Figura 6.2, “Operaciones de actualización y supresión para valores temporales.”.
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 (“Restricciones”), que restringen un valor temporal al complemento del valor de tiempo.
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 Figura 6.3, “Operaciones de modificación para tablas temporales en SQL.” 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 (Figura 6.1, “Operación de inserción para valores temporales.” y Figura 6.2, “Operaciones de actualización y supresión para valores temporales.”). 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
.
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]} */
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) → ttype
appendInstant(ttypeInst,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'); -- [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]} */
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 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 tgeogpoint
ya que 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, 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, 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]} */
Fusionar los valores temporales
merge(ttype,ttype) → ttype
merge(ttype[]) → ttype
Los valores temporales solo pueden intersectar en su límite y en ese caso, los valores de base en las marcas de tiempo comunes deben ser los mismos; de lo contrario, se genera un error.
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 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]