2009-06-02 8 views
5
site_id | start_date | end_date 
     1 | oct 1, 08 | oct 2, 08 
     1 | oct 2, 08 | oct 3, 08 
... 
     1 | oct 30, 08 | oct 31, 08 
     2 | oct 1, 08 | oct 2, 08 
     2 | oct 2, 08 | oct 3, 08 
... 
     2 | oct 30, 08 | oct 31, 08 

Tengo una tabla que contiene 1 registro por sitio por día del mes (por mes del año). Necesito poder determinar si un sitio para un mes determinado tiene al menos 15 registros contiguos, y necesito saber la fecha de inicio y finalización de esa serie de días contiguos. Puedo hacer esto en un procedimiento almacenado, pero esperaba que esto se pudiera lograr en una sola consulta. Estoy lidiando con un conjunto de datos bastante grande, al menos 30 millones de registros por mes.¿Cómo puedo consultar eficientemente conjuntos contiguos de fechas en mi conjunto de datos?

Ejemplo Resultados:

site_id | contiguous_start_date | contiguous_end_date 
     1 | oct 5, 2008   | oct 20, 2008 
     2 | oct 10    | oct 30, 2008 
     3 | oct 1     | oct 31, 2008 

gracias por su ayuda!

+0

¿Cuándo 'end_date' no es igual 'start_date + 1 day'? Porque la consulta es más simple si no hay necesidad de mirar ambas columnas. –

Respuesta

4

Aquí es un ejemplo de cómo hacer una consulta como:

SQL> create table t (site_id,start_date,end_date) 
    2 as 
    3 select 1, date '2008-10-01', date '2008-10-02' from dual union all 
    4 select 1, date '2008-10-02', date '2008-10-03' from dual union all 
    5 select 1, date '2008-10-03', date '2008-10-30' from dual union all 
    6 select 1, date '2008-10-30', date '2008-10-31' from dual union all 
    7 select 2, date '2008-10-01', date '2008-10-02' from dual union all 
    8 select 2, date '2008-10-02', date '2008-10-03' from dual union all 
    9 select 2, date '2008-10-03', date '2008-10-04' from dual union all 
10 select 2, date '2008-10-04', date '2008-10-05' from dual union all 
11 select 2, date '2008-10-05', date '2008-10-06' from dual union all 
12 select 2, date '2008-10-06', date '2008-10-07' from dual union all 
13 select 2, date '2008-10-07', date '2008-10-08' from dual union all 
14 select 2, date '2008-10-08', date '2008-10-09' from dual union all 
15 select 2, date '2008-10-09', date '2008-10-10' from dual union all 
16 select 2, date '2008-10-10', date '2008-10-11' from dual union all 
17 select 2, date '2008-10-11', date '2008-10-12' from dual union all 
18 select 2, date '2008-10-12', date '2008-10-13' from dual union all 
19 select 2, date '2008-10-13', date '2008-10-14' from dual union all 
20 select 2, date '2008-10-14', date '2008-10-15' from dual union all 
21 select 2, date '2008-10-15', date '2008-10-16' from dual union all 
22 select 2, date '2008-10-16', date '2008-10-17' from dual union all 
23 select 2, date '2008-10-17', date '2008-10-18' from dual union all 
24 select 2, date '2008-10-18', date '2008-10-19' from dual union all 
25 select 2, date '2008-10-19', date '2008-10-20' from dual union all 
26 select 3, date '2008-10-01', date '2008-10-02' from dual union all 
27 select 3, date '2008-10-02', date '2008-10-03' from dual union all 
28 select 3, date '2008-10-03', date '2008-10-04' from dual union all 
29 select 3, date '2008-10-04', date '2008-10-05' from dual union all 
30 select 3, date '2008-10-05', date '2008-10-06' from dual union all 
31 select 3, date '2008-10-06', date '2008-10-07' from dual union all 
32 select 3, date '2008-10-07', date '2008-10-08' from dual union all 
33 select 3, date '2008-10-08', date '2008-10-09' from dual union all 
34 select 3, date '2008-10-09', date '2008-10-10' from dual union all 
35 select 3, date '2008-10-30', date '2008-10-31' from dual 
36/

Tabel is aangemaakt. 

Y entonces la pregunta:

SQL> select site_id 
    2  , min(start_date) contiguous_start_date 
    3  , max(end_date) contiguous_end_date 
    4  , count(*) number_of_contiguous_records 
    5 from (select site_id 
    6    , start_date 
    7    , end_date 
    8    , max(rn) over (partition by site_id order by start_date) maxrn 
    9    from (select site_id 
10       , start_date 
11       , end_date 
12       , case lag(end_date) over (partition by site_id order by start_date) 
13        when start_date then null 
14        else rownum 
15       end rn 
16      from t 
17     ) 
18   ) 
19 group by site_id 
20  , maxrn 
21 order by site_id 
22  , contiguous_start_date 
23/

Y los resultados:

SITE_ID CONTIGUOUS_START_DA CONTIGUOUS_END_DATE NUMBER_OF_CONTIGUOUS_RECORDS 
---------- ------------------- ------------------- ---------------------------- 
     1 01-10-2008 00:00:00 31-10-2008 00:00:00       4 
     2 01-10-2008 00:00:00 20-10-2008 00:00:00       19 
     3 01-10-2008 00:00:00 10-10-2008 00:00:00       9 
     3 30-10-2008 00:00:00 31-10-2008 00:00:00       1 

4 rijen zijn geselecteerd. 

Saludos, Rob .

+0

Enfoque inteligente para resolver el problema. Gracias. –

+0

+1 Cool, lag (end_date) = start_date. – Andomar

1

Esto es definitivamente muy posible. Resolví un problema similar en SQL Server hace un par de meses. No sé nada de la sintaxis de Oracle, así que me temo que no puedo convertirlo para ti, pero si eres sólido con Oracle, this debería ser suficiente para llevarte allí.

-1

Su estructura de base de datos no es adecuado para la lógica de negocio que tiene:

  • fecha_final es siempre el día siguiente después de fecha_inicial entonces ¿por qué hay que almacenarlo en el PP?
  • Veo que en la muestra de datos que proporcionó no hay espacios en el rango de fechas para un solo sitio. Eso significa que no tiene que almacenar el período de todas las fechas solo para iniciar y detener la fecha.

30 millones de discos al mes es realmente mesa para la consulta que tiene que escribir. Haga una refacturación estructural de esta tabla es mi consejo.

Cuestiones relacionadas