Sql 从不规则日期中按小时查找时间百分比
我有一个如下表,每个条目在给定的时间内状态发生变化。 该状态可以重复,因为其他列具有子状态信息 我怎样才能得到每个状态的百分比时间,比如说,小时Sql 从不规则日期中按小时查找时间百分比,sql,oracle,datetime,intervals,Sql,Oracle,Datetime,Intervals,我有一个如下表,每个条目在给定的时间内状态发生变化。 该状态可以重复,因为其他列具有子状态信息 我怎样才能得到每个状态的百分比时间,比如说,小时 NAME STATUS_CHANGE_TIME STATUS foo 15-MAY-11 18:52 A foo 15-MAY-11 18:38 A foo 15-MAY-11 18:33 B foo 15-MAY-11 16:53 A foo 15-MAY-11 16:47 B foo 15-MA
NAME STATUS_CHANGE_TIME STATUS
foo 15-MAY-11 18:52 A
foo 15-MAY-11 18:38 A
foo 15-MAY-11 18:33 B
foo 15-MAY-11 16:53 A
foo 15-MAY-11 16:47 B
foo 15-MAY-11 13:37 A
foo 15-MAY-11 13:33 C
foo 15-MAY-11 10:23 C
foo 15-MAY-11 10:17 A
foo ...
期望回报:
HH24 STATUS PERCENT
10 ...
11 C 100 (No entries; last change was to C)
12 C 100 "" ""
13 C 62
13 A 38 (From C to A at :37 with 23 mins left; 23/60 ~ 38%)
14 A 100
15 A 100
16 A 90 (= A for first 47 minutes, then for another 7)
16 B 10 (16:53 - 16:47 = 6 minutes or 10% of an hour)
17 A 100
18 ... etc.
好问题,这是一个有趣的挑战 您需要的是一个辅助表来存储每个时间分区(在本例中为小时),然后在状态更新重叠的地方加入到该表中。LEAD可以抓取下一个状态条目来检查它是何时出现的,并且最大值和最小值可以确定每小时状态的开始/结束时间 当然,这在一个例子中更容易解释。以下是所需的工时表:
SQL> CREATE TABLE hours (HOUR NUMBER(2), start_m date, end_m date);
Table created.
SQL> BEGIN
2 FOR i IN 0..23 LOOP
3 INSERT INTO hours VALUES(i, to_date(lpad(i, 2, '0')||':00:00', 'HH24:MI:SS')
4 , to_date(lpad(i, 2, '0')||':59:59', 'HH24:MI:SS'));
5 END loop;
6 COMMIT;
7 END;
8 /
PL/SQL procedure successfully completed.
以下是您的问题中测试数据的总体
SQL> CREATE TABLE status_updates (NAME VARCHAR2(3), status_change_time DATE, status CHAR(1));
Table created.
SQL> INSERT INTO status_updates VALUES ('foo',TO_DATE('15-MAY-11 18:52', 'DD-MON-RR HH24:MI:SS'), 'A');
1 row created.
SQL> INSERT INTO status_updates VALUES ('foo',TO_DATE('15-MAY-11 18:38', 'DD-MON-RR HH24:MI:SS'), 'A');
1 row created.
SQL> INSERT INTO status_updates VALUES ('foo',TO_DATE('15-MAY-11 18:33', 'DD-MON-RR HH24:MI:SS'), 'B');
1 row created.
SQL> INSERT INTO status_updates VALUES ('foo',TO_DATE('15-MAY-11 16:53', 'DD-MON-RR HH24:MI:SS'), 'A');
1 row created.
SQL> INSERT INTO status_updates VALUES ('foo',TO_DATE('15-MAY-11 16:47', 'DD-MON-RR HH24:MI:SS'), 'B');
1 row created.
SQL> INSERT INTO status_updates VALUES ('foo',TO_DATE('15-MAY-11 13:37', 'DD-MON-RR HH24:MI:SS'), 'A');
1 row created.
SQL> INSERT INTO status_updates VALUES ('foo',TO_DATE('15-MAY-11 13:33', 'DD-MON-RR HH24:MI:SS'), 'C');
1 row created.
SQL> INSERT INTO status_updates VALUES ('foo',TO_DATE('15-MAY-11 10:23', 'DD-MON-RR HH24:MI:SS'), 'C');
1 row created.
SQL> INSERT INTO status_updates VALUES ('foo',TO_DATE('15-MAY-11 10:17', 'DD-MON-RR HH24:MI:SS'), 'A');
1 row created.
SQL> commit;
Commit complete.
下面是select语句,用于获取所需的百分比
SELECT t.NAME, t.HOUR, t.status, sum(round((status_end_h-start_status_h)*24*100)) per_cent
FROM (
SELECT A.NAME
, A.status
, A.status_change_time
, A.next_change_time
, b.HOUR
, greatest(status_change_time, trunc(status_change_time)+(b.start_m-trunc(b.start_m))) start_status_h
, least(next_change_time, trunc(next_change_time)+(b.end_m-trunc(b.end_m))) status_end_h
FROM (
SELECT NAME
, status
, status_change_time
, lead(status_change_time) OVER (ORDER BY NAME, status_change_time) next_change_time
FROM status_updates
) A, hours b
WHERE TO_CHAR(b.start_m, 'HH24:MI:SS') BETWEEN TO_CHAR(A.status_change_time, 'HH24:MI:SS') AND TO_CHAR(A.next_change_time, 'HH24:MI:SS')
OR TO_CHAR(b.end_m, 'HH24:MI:SS') BETWEEN TO_CHAR(A.status_change_time, 'HH24:MI:SS') AND TO_CHAR(A.next_change_time, 'HH24:MI:SS')
OR (TO_CHAR(A.status_change_time, 'HH24:MI:SS') BETWEEN TO_CHAR(b.start_m, 'HH24:MI:SS') AND TO_CHAR(b.end_m, 'HH24:MI:SS')
AND TO_CHAR(A.next_change_time, 'HH24:MI:SS') BETWEEN TO_CHAR(b.start_m, 'HH24:MI:SS') AND TO_CHAR(b.end_m, 'HH24:MI:SS'))
) t
GROUP BY t.NAME, t.HOUR, t.status
ORDER BY t.HOUR;
NAM HOUR S PER_CENT
--- ---------- - ----------
foo 10 A 10
foo 10 C 62
foo 11 C 100
foo 12 C 100
foo 13 A 38
foo 13 C 62
foo 14 A 100
foo 15 A 100
foo 16 A 90
foo 16 B 10
foo 17 A 100
NAM HOUR S PER_CENT
--- ---------- - ----------
foo 18 A 78
foo 18 B 8
13 rows selected.
很好的解决方案。您不一定需要额外的表-您可以在查询中动态生成它,例如,使用SELECT ROWNUM FROM DUAL CONNECT BY LEVEL@Jeffrey Kemp,我必须阅读您的建议。我没有使用“按级别连接”。听起来很有趣!对于未来的读者,我使用以下查询来使用Jeffrey Kemp的建议生成小时表:-生成小时表0-23以及每个小时的开始和结束时间。按级别从双连接中选择ROWNUM-1小时、truncsysdate+ROWNUM-1/24开始、truncsysdate+ROWNUM-1/24+0.0416550925926/*59:59*/end\m