2009-10-05 25 views
5

que tienen un conjunto de datos que contiene:PostgreSQL y secuencial de datos

Table { date itemName } 

La fecha en su mayor parte es secuencial. No hay duplicados de la fecha [ya que es la clave principal].

La pregunta se divide en varias partes (todo con respecto al uso de SQL):

  1. ¿Es posible encontrar lagunas en la serie fecha indicada en la tabla? Por ejemplo: Fechas 1/2/09-1/3/09 faltan
  2. ¿Es posible encontrar secciones de fechas que faltan en la tabla, que tiene un rango mayor que n (este es un número determinado en tiempo de ejecución)? Por ejemplo: para n = 2 Las fechas 1/2/09-1/3/09 no se devuelven pero las fechas 5/6/09-6/1/09 son.
+0

Mi enfoque sería el procesamiento posterior de los resultados .. http://jeremy.zawodny.com/blog/archives/010523.html ... pero si es posible dentro de la consulta, y no afecta demasiado al sistema, sería genial :) – warren

+0

Esta no es una consulta en vivo que se usará a menudo, es solo para mantenimiento de una vez y Un rato. – monksy

Respuesta

1

Simplemente cree una función en plsql o en un cliente que verificará todas las fechas. Al igual que este pseudocódigo:

date checked_date = 2000-01-01; 
int unchecked_section = 0; 
while (checked_date <= today()) { 
    if (! sql(select itemName from Table where itemName=checked_date)) { 
    unchecked_section++; 
    } else { 
    if (unchecked_section>=n) { 
     print checked_date-unchecked_section, checked_date 
    } 
    unchecked_section = 0; 
    } 
    checked_date++; 
} 
if (unchecked_section) { 
    print checked_date-unchecked_section, checked_date 
} 

No tiene que ser muy rápido, ya que es el mantenimiento solamente. No hay muchas fechas para verificar, solo 365 por año.

+0

Si no tiene funciones de ventana de SQL disponibles, este enfoque es el más rápido posible en un conjunto de datos grande, ya que solo hace una pasada sobre la mesa. Una cosa que debe observar es que SELECT obtiene ORDER BY para que las filas aparezcan ordenadas. Y debe usar "SELECCIONAR min (fecha), max (fecha) de la tabla" para obtener los límites de bucle: presumir que las cosas terminan en "hoy" no es la mejor idea. PostgreSQL tiene muchos lenguajes de programación disponibles que puede ejecutar dentro de la base de datos, PL/pgSQL es el estándar. –

1

Después de algunas pruebas que se le ocurrió la siguiente instrucción SQL:

SELECT date, itemName 
    FROM "Table" as t1 
    WHERE NOT EXISTS (
    SELECT date 
    FROM "Table" as t2 
    WHERE t2.date = (t1.date - INTERVAL '1 day') 
) 
    ORDER BY date 
    OFFSET 1 -- this will skip the first element 

Esto le dará todas las filas que no tienen ningún sucesor directo.

Si modifica la declaración:

SELECT date, itemName 
    FROM "Table" as t1 
    WHERE NOT EXISTS (
    SELECT date 
    FROM "Table" as t2 
    WHERE (t2.date >= (t1.date - INTERVAL '2 day')) 
    AND (t2.date < t1.date) 
) 
    ORDER BY date 
    OFFSET 1 

puede utilizar la longitud del intervalo en la cláusula dónde está la subselección para filtrar por huecos de al menos ese tamaño.

Espero que ayude.

+0

El tiempo de ejecución de esto es proporcional al cuadrado del tamaño de la tabla, porque tanto la SELECCION ajena como la subconsulta EXISTS interna están haciendo cosas cuyo tiempo de ejecución es proporcional al tamaño de la tabla. Eso puede parecer razonable al principio, pero eventualmente se volverá realmente caro. Desafortunadamente, cualquier otra solución que haga en SQL directo va a sufrir el mismo problema, porque SQL no tiene memoria de fila. Para una tabla de n-filas, debe hacer una n X n unirse de alguna forma para resolver este tipo de problema. Cuando están disponibles, las funciones de ventana son las mejores en este aspecto. –

+0

@Greg: gracias por el análisis.tienes razón, esta no es la solución más rápida, si las funciones de Windows están a la mano. Pero PostgreSQL 8.4 es una versión bastante reciente, por lo que hay posibilidades, el OP está usando una versión anterior. Consulte también los comentarios de OP sobre su pregunta para conocer sus requisitos de rendimiento en tiempo de ejecución. –

10

Si puede utilizar PostgreSQL 8.4 a continuación le ayudará window functions:

SELECT * 
    FROM (SELECT itemName, date, date - lag(date) OVER w AS gap 
       FROM someTable WINDOW w AS (ORDER BY date) 
     ) AS pairs 
    WHERE pairs.gap > '1 day'::interval; 
+0

Este es exactamente el tipo de problemas que las funciones de ventana intentan resolver de manera eficiente, y no hay otra solución solo de SQL que pueda ejecutarse tan rápido como esto. –

+0

Lamentablemente, no tengo la versión 8.4. Tengo 8.1. Ojalá pudiera obtener crédito a esta respuesta. Me gusta mucho. – monksy