Oracle - SQL,从日期范围内提取时间范围

发布于 2024-12-11 04:31:30 字数 3219 浏览 0 评论 0原文

我正在尝试编写一个选择语句来返回特定日期范围内特定时间范围内的平均值。例如,我想知道过去 7 天下午 4 点至晚上 11 点、全天以及上午 8 点至下午 6 点时间范围内的 avg(max_percent_util)。这是我到目前为止所拥有的,我不确定查询此时是否会结束。

select 
sdpt.DOWN_DESC, 
avg(sdpt.max_percent_util) seven_day_prime,
avg(sday.max_percent_util) seven_day,
avg(sdb.max_percent_util) seven_day_business

from 

(select down_desc, hour_stamp, max_percent_util from downstream_hour_facts 
where ((hour_stamp >= sysdate-8 AND to_char(hour_stamp, 'HH24:MI') >= '16:00' AND to_char(hour_stamp, 'HH24:MI') <= '23:00')
or (hour_stamp >= sysdate-7 AND to_char(hour_stamp, 'HH24:MI') >= '16:00' AND to_char(hour_stamp, 'HH24:MI') <= '23:00')
or (hour_stamp >= sysdate-6 AND to_char(hour_stamp, 'HH24:MI') >= '16:00' AND to_char(hour_stamp, 'HH24:MI') <= '23:00')
or (hour_stamp >= sysdate-5 AND to_char(hour_stamp, 'HH24:MI') >= '16:00' AND to_char(hour_stamp, 'HH24:MI') <= '23:00')
or (hour_stamp >= sysdate-4 AND to_char(hour_stamp, 'HH24:MI') >= '16:00' AND to_char(hour_stamp, 'HH24:MI') <= '23:00')
or (hour_stamp >= sysdate-3 AND to_char(hour_stamp, 'HH24:MI') >= '16:00' AND to_char(hour_stamp, 'HH24:MI') <= '23:00')
or (hour_stamp >= sysdate-2 AND to_char(hour_stamp, 'HH24:MI') >= '16:00' AND to_char(hour_stamp, 'HH24:MI') <= '23:00')
or (hour_stamp >= sysdate-1 AND to_char(hour_stamp, 'HH24:MI') >= '16:00' AND to_char(hour_stamp, 'HH24:MI') <= '23:00'))) sdpt,

(select down_desc, hour_stamp, max_percent_util from downstream_hour_facts 
where ((hour_stamp >= sysdate-8) or (hour_stamp >= sysdate-7) or (hour_stamp >= sysdate-6)
or (hour_stamp >= sysdate-5) or (hour_stamp >= sysdate-4) or (hour_stamp >= sysdate-3)
or (hour_stamp >= sysdate-2) or (hour_stamp >= sysdate-1))) sday,

(select down_desc, hour_stamp, max_percent_util from downstream_hour_facts 
where ((hour_stamp >= sysdate-8 AND to_char(hour_stamp, 'HH24:MI') >= '8:00' AND to_char(hour_stamp, 'HH24:MI') <= '18:00')
or (hour_stamp >= sysdate-7 AND to_char(hour_stamp, 'HH24:MI') >= '08:00' AND to_char(hour_stamp, 'HH24:MI') <= '18:00')
or (hour_stamp >= sysdate-6 AND to_char(hour_stamp, 'HH24:MI') >= '08:00' AND to_char(hour_stamp, 'HH24:MI') <= '18:00')
or (hour_stamp >= sysdate-5 AND to_char(hour_stamp, 'HH24:MI') >= '08:00' AND to_char(hour_stamp, 'HH24:MI') <= '18:00')
or (hour_stamp >= sysdate-4 AND to_char(hour_stamp, 'HH24:MI') >= '08:00' AND to_char(hour_stamp, 'HH24:MI') <= '18:00')
or (hour_stamp >= sysdate-3 AND to_char(hour_stamp, 'HH24:MI') >= '08:00' AND to_char(hour_stamp, 'HH24:MI') <= '18:00')
or (hour_stamp >= sysdate-2 AND to_char(hour_stamp, 'HH24:MI') >= '08:00' AND to_char(hour_stamp, 'HH24:MI') <= '18:00')
or (hour_stamp >= sysdate-1 AND to_char(hour_stamp, 'HH24:MI') >= '08:00' AND to_char(hour_stamp, 'HH24:MI') <= '18:00'))) sdb
where sdpt.down_desc = sday.down_desc and sday.down_desc = sdb.down_desc
group by sdpt.DOWN_DESC
order by sdpt.down_desc

我希望重新创建的示例输出:

  • 指标:过去 24 小时的利用率数据
  • :7.15%
  • 7 天滚动(所有小时):7.12%
  • 7 天滚动黄金时段 (4-12):7.12%
  • 7 天滚动营业时间(9-5): 7.12%

I'm trying to write a select statement to return average values over a specific time range over a specific date range. For example I'd like to know the avg(max_percent_util) over the past 7 days during the time frames 4pm-11pm, all day, and 8am-6pm. This is what I have so far and I'm not sure the query will ever end at this point.

select 
sdpt.DOWN_DESC, 
avg(sdpt.max_percent_util) seven_day_prime,
avg(sday.max_percent_util) seven_day,
avg(sdb.max_percent_util) seven_day_business

from 

(select down_desc, hour_stamp, max_percent_util from downstream_hour_facts 
where ((hour_stamp >= sysdate-8 AND to_char(hour_stamp, 'HH24:MI') >= '16:00' AND to_char(hour_stamp, 'HH24:MI') <= '23:00')
or (hour_stamp >= sysdate-7 AND to_char(hour_stamp, 'HH24:MI') >= '16:00' AND to_char(hour_stamp, 'HH24:MI') <= '23:00')
or (hour_stamp >= sysdate-6 AND to_char(hour_stamp, 'HH24:MI') >= '16:00' AND to_char(hour_stamp, 'HH24:MI') <= '23:00')
or (hour_stamp >= sysdate-5 AND to_char(hour_stamp, 'HH24:MI') >= '16:00' AND to_char(hour_stamp, 'HH24:MI') <= '23:00')
or (hour_stamp >= sysdate-4 AND to_char(hour_stamp, 'HH24:MI') >= '16:00' AND to_char(hour_stamp, 'HH24:MI') <= '23:00')
or (hour_stamp >= sysdate-3 AND to_char(hour_stamp, 'HH24:MI') >= '16:00' AND to_char(hour_stamp, 'HH24:MI') <= '23:00')
or (hour_stamp >= sysdate-2 AND to_char(hour_stamp, 'HH24:MI') >= '16:00' AND to_char(hour_stamp, 'HH24:MI') <= '23:00')
or (hour_stamp >= sysdate-1 AND to_char(hour_stamp, 'HH24:MI') >= '16:00' AND to_char(hour_stamp, 'HH24:MI') <= '23:00'))) sdpt,

(select down_desc, hour_stamp, max_percent_util from downstream_hour_facts 
where ((hour_stamp >= sysdate-8) or (hour_stamp >= sysdate-7) or (hour_stamp >= sysdate-6)
or (hour_stamp >= sysdate-5) or (hour_stamp >= sysdate-4) or (hour_stamp >= sysdate-3)
or (hour_stamp >= sysdate-2) or (hour_stamp >= sysdate-1))) sday,

(select down_desc, hour_stamp, max_percent_util from downstream_hour_facts 
where ((hour_stamp >= sysdate-8 AND to_char(hour_stamp, 'HH24:MI') >= '8:00' AND to_char(hour_stamp, 'HH24:MI') <= '18:00')
or (hour_stamp >= sysdate-7 AND to_char(hour_stamp, 'HH24:MI') >= '08:00' AND to_char(hour_stamp, 'HH24:MI') <= '18:00')
or (hour_stamp >= sysdate-6 AND to_char(hour_stamp, 'HH24:MI') >= '08:00' AND to_char(hour_stamp, 'HH24:MI') <= '18:00')
or (hour_stamp >= sysdate-5 AND to_char(hour_stamp, 'HH24:MI') >= '08:00' AND to_char(hour_stamp, 'HH24:MI') <= '18:00')
or (hour_stamp >= sysdate-4 AND to_char(hour_stamp, 'HH24:MI') >= '08:00' AND to_char(hour_stamp, 'HH24:MI') <= '18:00')
or (hour_stamp >= sysdate-3 AND to_char(hour_stamp, 'HH24:MI') >= '08:00' AND to_char(hour_stamp, 'HH24:MI') <= '18:00')
or (hour_stamp >= sysdate-2 AND to_char(hour_stamp, 'HH24:MI') >= '08:00' AND to_char(hour_stamp, 'HH24:MI') <= '18:00')
or (hour_stamp >= sysdate-1 AND to_char(hour_stamp, 'HH24:MI') >= '08:00' AND to_char(hour_stamp, 'HH24:MI') <= '18:00'))) sdb
where sdpt.down_desc = sday.down_desc and sday.down_desc = sdb.down_desc
group by sdpt.DOWN_DESC
order by sdpt.down_desc

Example output that i'm looking to re-create:

  • Metric: Utilization Data
  • Previous 24 Hours: 7.15%
  • 7 Day Rolling (all hours): 7.12%
  • 7 Day Rolling Prime Time (4-12): 7.12%
  • 7 Day Rolling Business Hours (9-5): 7.12%

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

栀梦 2024-12-18 04:31:30

您的查询如此缓慢的原因之一是您没有比较日期,而是比较字符串;使用 TO_CHAR()。你还做了很多多余的工作。

下面是一个示例,它解析数据一次(而不是三次),避免字符串比较,因此应该快速将数据过滤到您想要的 8 天和一点天。

WITH
  filtered_data AS
(
  SELECT
    down_desc,
    hour_stamp,
    TRUNC(hour_stamp)                date_stamp,
    hour_stamp - TRUNC(hour_stamp)   time_stamp
  FROM
    downstream_hour_facts
  WHERE
    hour_stamp >= TRUNC(sysdate) - 8
)
SELECT
  down_desc,
  AVG(CASE WHEN date_stamp >= TRUNC(sysdate)
           THEN max_percent ELSE NULL END)          today,
  AVG(CASE WHEN date_stamp <  TRUNC(sysdate)
           THEN max_percent ELSE NULL END)          seven_day_all,
  AVG(CASE WHEN date_stamp <  TRUNC(sysdate)
            AND time_stamp >= TO_TIMESTAMP('16:00', 'HH24:MI')
            AND time_stamp <  TO_TIMESTAMP('23:00', 'HH24:MI')
           THEN max_percent ELSE NULL END)          seven_day_prime,
  AVG(CASE WHEN date_stamp <  TRUNC(sysdate)
            AND time_stamp >= TO_TIMESTAMP('08:00', 'HH24:MI')
            AND time_stamp <  TO_TIMESTAMP('16:00', 'HH24:MI')
           THEN max_percent ELSE NULL END)          seven_day_business
FROM
  filtered_data
GROUP BY
  down_desc
ORDER BY
  down_desc

编辑

我还注意到您正在以“危险”的错误方式连接数据...

子查询 1 可能会返回某个指标的 9 条记录。
子查询 2 可能会返回该指标的 3 条记录。
子查询 3 可能会返回该指标的 4 条记录。

但随后您通过指标加入它们。 SQ1 中的所有 9 条记录都与 SQ2 中的所有 3 条记录(现在 27 条记录)相匹配,并且所有记录都与 SQ3 中的所有 4 条记录(现在 108 条记录)相匹配。

连接数据集时要非常小心,确保每条记录都连接到需要的位置,并且仅连接到需要的位置。

(无论如何,上面的单一解析版本应该完全避免这个问题。)

One reason that your query isso slow is that you're not camparing dates, you're comparing strings; using TO_CHAR(). You're also doing a lot of redundant work.

Here is an example that parses the data once (not three times), avoids string comparisons, and so should quickly filter the data down to the 8 and a bit days you want.

WITH
  filtered_data AS
(
  SELECT
    down_desc,
    hour_stamp,
    TRUNC(hour_stamp)                date_stamp,
    hour_stamp - TRUNC(hour_stamp)   time_stamp
  FROM
    downstream_hour_facts
  WHERE
    hour_stamp >= TRUNC(sysdate) - 8
)
SELECT
  down_desc,
  AVG(CASE WHEN date_stamp >= TRUNC(sysdate)
           THEN max_percent ELSE NULL END)          today,
  AVG(CASE WHEN date_stamp <  TRUNC(sysdate)
           THEN max_percent ELSE NULL END)          seven_day_all,
  AVG(CASE WHEN date_stamp <  TRUNC(sysdate)
            AND time_stamp >= TO_TIMESTAMP('16:00', 'HH24:MI')
            AND time_stamp <  TO_TIMESTAMP('23:00', 'HH24:MI')
           THEN max_percent ELSE NULL END)          seven_day_prime,
  AVG(CASE WHEN date_stamp <  TRUNC(sysdate)
            AND time_stamp >= TO_TIMESTAMP('08:00', 'HH24:MI')
            AND time_stamp <  TO_TIMESTAMP('16:00', 'HH24:MI')
           THEN max_percent ELSE NULL END)          seven_day_business
FROM
  filtered_data
GROUP BY
  down_desc
ORDER BY
  down_desc

EDIT

I've also noticed that you're joinging the data in a 'dangerously' incorrect way...

Sub Query 1 may return 9 records for a metric.
Sub Query 2 may return 3 records for that metric.
Sub Query 3 may return 4 records for that metric.

But then you join them only by the metric. All 9 records from SQ1 match all 3 from SQ2 (27 records now), and all of them match all 4 from SQ3 (108 records now).

When joining sets of data be very careful that each record joins to where it's needed, and only where it's needed.

(The single parse version above should totally avoid that problem anyway.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文