2011-06-01 11 views
7

Tengo una tabla events con dos columnas eventkey (única, clave principal) y createtime, que almacena la hora de creación del evento como el número de milisegundos desde el 1 de enero de 1970 en una columna NUMBER.¿Forma óptima de crear una distribución de histograma/frecuencia en Oracle?

Me gustaría crear un "histograma" o distribución de frecuencia que me muestre cuántos eventos se crearon en cada hora de la semana pasada.

¿Es esta la mejor manera de escribir una consulta de este tipo en Oracle, utilizando la función width_bucket()? ¿Es posible derivar el número de filas que caen en cada segmento usando una de las otras funciones analíticas de Oracle en lugar de usar width_bucket para determinar a qué número de segmento pertenece cada fila y hacer un count(*) sobre eso?

-- 1305504000000 = 5/16/2011 12:00am GMT 
-- 1306108800000 = 5/23/2011 12:00am GMT 
select 
timestamp '1970-01-01 00:00:00' + numtodsinterval((1305504000000/1000 + (bucket * 60 * 60)), 'second') period_start, 
numevents 
from (
    select bucket, count(*) as events from (
    select eventkey, createtime, 
    width_bucket(createtime, 1305504000000, 1306108800000, 24 * 7) bucket 
    from events 
    where createtime between 1305504000000 and 1306108800000 
) group by bucket 
) 
order by period_start 

Respuesta

10

Si su createtime eran una columna de fecha, esto sería trivial:

SELECT TO_CHAR(CREATE_TIME, 'DAY:HH24'), COUNT(*) 
    FROM EVENTS 
GROUP BY TO_CHAR(CREATE_TIME, 'DAY:HH24'); 

Como es, echando la columna de la createtime no es demasiado difícil:

select TO_CHAR( 
     TO_DATE('19700101', 'YYYYMMDD') + createtime/86400000), 
     'DAY:HH24') AS BUCKET, COUNT(*) 
    FROM EVENTS 
    WHERE createtime between 1305504000000 and 1306108800000 
group by TO_CHAR( 
     TO_DATE('19700101', 'YYYYMMDD') + createtime/86400000), 
     'DAY:HH24') 
order by 1 

Si, alternativamente, está buscando los valores del poste de la cerca (por ejemplo, ¿a dónde voy desde el primer decil (0-10%)?) A la siguiente (11-20%), que haría algo como:

select min(createtime) over (partition by decile) as decile_start, 
     max(createtime) over (partition by decile) as decile_end, 
     decile 
    from (select createtime, 
       ntile (10) over (order by createtime asc) as decile 
      from events 
     where createtime between 1305504000000 and 1306108800000 
     ) 
+0

esto funciona bien, gracias. No estoy seguro de por qué no pensé simplemente en truncar las fechas en primer lugar, creo que me puse tan al corriente de cómo analizar y emitir este extraño formato de "fecha" –

+0

¿Hay alguna forma de mantener filas para create_times que tengan un conteo cero? –

3

estoy familiarizado con las funciones de fecha de Oracle, pero estoy bastante seguro de que hay una manera equivalente a escribir esta declaración Postgres:

select date_trunc('hour', stamp), count(*) 
from your_data 
group by date_trunc('hour', stamp) 
order by date_trunc('hour', stamp) 
+1

¡Funciona perfectamente en PG! Muy rápido también –

1

más o menos la misma respuesta que Adán, pero yo preferiría mantener el period_start como un campo de tiempo por lo que es más fácil de filtrar aún más si es necesario:

with 
events as 
(
    select rownum eventkey, round(dbms_random.value(1305504000000, 1306108800000)) createtime 
    from dual 
    connect by level <= 1000 
) 
select 
    trunc(timestamp '1970-01-01 00:00:00' + numtodsinterval(createtime/1000, 'second'), 'HH') period_start, 
    count(*) numevents 
from 
    events 
where 
    createtime between 1305504000000 and 1306108800000 
group by 
    trunc(timestamp '1970-01-01 00:00:00' + numtodsinterval(createtime/1000, 'second'), 'HH') 
order by 
    period_start 
+0

¿Puedes explicar el propósito de la porción 'with events as()' y por qué estás seleccionando valores aleatorios? No estoy muy familiarizado con la sintaxis de Oracle –

+0

lo siento ... Como no tengo su tabla de datos para ejecutar la consulta, estoy generando datos aleatorios para emular lo que podría estar en su tabla. La declaración "con eventos" solo me permite aliar esa consulta como "eventos" para que el resto de la consulta coincida con lo que podría usar directamente en su tabla de eventos sin realizar ningún cambio. Para sus propósitos, simplemente elimine todo lo anterior "seleccionar trunc (...." – Craig

+0

ah gracias, veo cómo eso sería útil en este tipo de respuesta :) –

Cuestiones relacionadas