7

我有一个events包含两列eventkey(唯一、主键)和的表createtime,它将事件的创建时间存储为自 1970 年 1 月 1 日以来的毫秒数NUMBER

我想创建一个“直方图”或频率分布,显示过去一周的每个小时内创建了多少事件。

width_bucket()这是使用该函数在 Oracle 中编写此类查询的最佳方法吗?是否可以使用其他 Oracle 分析函数之一导出落入每个存储桶的行数,而不是使用width_bucket来确定每行属于哪个存储桶编号并count(*)对其进行处理?

-- 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
4

4 回答 4

11

如果你createtime是一个日期列,这将是微不足道的:

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

事实上,铸造createtime柱子并不太难:

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

或者,如果您正在寻找 fencepost 值(例如,我从第一个十分位数 (0-10%) 到下一个十分位数 (11-20%) 的位置,您可以执行以下操作:

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
       )
于 2011-06-01T13:47:22.577 回答
3

我不熟悉 Oracle 的日期函数,但我很确定有一种等效的方式来编写这个 Postgres 语句:

select date_trunc('hour', stamp), count(*)
from your_data
group by date_trunc('hour', stamp)
order by date_trunc('hour', stamp)
于 2011-06-01T13:47:57.720 回答
1

与 Adam 的响应几乎相同,但我更愿意将 period_start 保留为时间字段,以便在需要时更容易进一步过滤:

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
于 2011-06-01T13:59:56.793 回答
0

使用 oracle 提供的函数“ WIDTH_BUCKET ”来累积连续或精细离散的数据。以下示例显示了一种创建具有 5 个存储桶的直方图并从 510 到 520 收集“COLUMN_VALUE”的方法(因此每个存储桶获取范围为 2 的值)。WIDTH_BUCKET 将为低于最小值和高于最大值的值创建额外的 id=0 和 num_buckets+1 个桶。

SELECT "BUCKET_ID", count(*), 
CASE
    WHEN "BUCKET_ID"=0 THEN -1/0F
    ELSE 510+(520-510)/5*("BUCKET_ID"-1)
END "BUCKET_MIN",
CASE
    WHEN "BUCKET_ID"=5+1 THEN 1/0F
    ELSE 510+(520-510)/5*("BUCKET_ID")
END "BUCKET_MAX"
FROM 
(
    SELECT  "COLUMN_VALUE", 
            WIDTH_BUCKET("COLUMN_VALUE", 510, 520, 5) "BUCKET_ID"
    FROM "MY_TABLE"
)
group by "BUCKET_ID"
ORDER BY "BUCKET_ID";

样本输出

 BUCKET_ID   COUNT(*) BUCKET_MIN BUCKET_MAX
---------- ---------- ---------- ----------
         0         45       -Inf   5.1E+002
         1        220   5.1E+002  5.12E+002
         2        189  5.12E+002  5.14E+002
         3         43  5.14E+002  5.16E+002
         4          3  5.16E+002  5.18E+002

在我的表中,没有 518-520,所以没有显示 id=5 的存储桶。另一方面,有低于 min (510) 的值,所以有一个 id=0 的存储桶,将 -inf 收集到 510 个值。

于 2019-11-25T02:42:28.917 回答