【问题标题】:Transform from timestamped records to 15 minute periodic records从时间戳记录转换为 15 分钟定期记录
【发布时间】:2021-01-29 15:19:38
【问题描述】:

我有与建筑物内带有 RFID 标记的资产的位置相关的记录。记录具有开始和结束时间戳以及资产在这两个时间戳之间的位置。

<table>
  <tr>
    <td>ZONEID</td>
    <td>MACADDRESS</td>
    <td>START_TS</td>
    <td>END_TS</td>
  </tr>
  <tr>
    <td>SJC20-3-NZ-4</td>
    <td>00:00:04:be:23:7c</td>
    <td>13/10/20 07:00:30.000000000 AM</td>
    <td>13/10/20 07:04:26.000000000 AM</td>
  </tr>
  <tr>
    <td>SJC20-3-NZ-4</td>
    <td>00:00:04:be:23:7c</td>
    <td>13/10/20 07:04:26.000000000 AM</td>
    <td>13/10/20 07:04:28.000000000 AM</td>
  </tr>
  <tr>
    <td>SJC20-3-NZ-5</td>
    <td>00:00:04:be:23:7c</td>
    <td>13/10/20 07:04:28.000000000 AM</td>
    <td>13/10/20 07:14:49.000000000 AM</td>
  </tr>
  <tr>
    <td>SJC20-3-NZ-5</td>
    <td>00:00:04:be:23:7c</td>
    <td>13/10/20 07:14:49.000000000 AM</td>
    <td>13/10/20 07:15:08.000000000 AM</td>
  </tr>
  <tr>
    <td>SJC20-3-NZ-5</td>
    <td>00:00:04:be:23:7c</td>
    <td>13/10/20 07:15:08.000000000 AM</td>
    <td>13/10/20 07:16:49.000000000 AM</td>
  </tr>
  <tr>
    <td>SJC20-3-NZ-6</td>
    <td>00:00:04:be:23:7c</td>
    <td>13/10/20 07:16:49.000000000 AM</td>
    <td>13/10/20 07:17:17.000000000 AM</td>
  </tr>
  <tr>
    <td>SJC20-3-NZ-6</td>
    <td>00:00:04:be:23:7c</td>
    <td>13/10/20 07:17:17.000000000 AM</td>
    <td>13/10/20 07:19:09.000000000 AM</td>
  </tr>
  <tr>
    <td>SJC20-3-NZ-6</td>
    <td>00:00:04:be:23:7c</td>
    <td>13/10/20 07:19:09.000000000 AM</td>
    <td>13/10/20 07:19:22.000000000 AM</td>
  </tr>
</table>

我想对此进行转换,以便在一天中每 15 分钟间隔,我可以说出每个资产在检测到的每个位置花费了多少分钟。如下所示,我需要在 Oracle SQL 中执行此操作。

<table>
  <tr>
    <td>ZONEID</td>
    <td>MACADDRESS</td>
    <td>START_TS</td>
    <td>END_TS</td>
    <td>TIME_MINS</td>
  </tr>
  <tr>
    <td>SJC20-3-NZ-4</td>
    <td>00:00:04:be:23:7c</td>
    <td>13/10/20 07:00:00.000000000 AM</td>
    <td>13/10/20 07:15:00.000000000 AM</td>
    <td>4</td>
  </tr>
  <tr>
    <td>SJC20-3-NZ-5</td>
    <td>00:00:04:be:23:7c</td>
    <td>13/10/20 07:00:00.000000000 AM</td>
    <td>13/10/20 07:15:00.000000000 AM</td>
    <td>11</td>
  </tr>
  <tr>
    <td>SJC20-3-NZ-5</td>
    <td>00:00:04:be:23:7c</td>
    <td>13/10/20 07:15:00.000000000 AM</td>
    <td>13/10/20 07:30:00.000000000 AM</td>
    <td>1</td>
  </tr>
  <tr>
    <td>SJC20-3-NZ-6</td>
    <td>00:00:04:be:23:7c</td>
    <td>13/10/20 07:15:00.000000000 AM</td>
    <td>13/10/20 07:30:00.000000000 AM</td>
    <td>4</td>
  </tr>
</table>

【问题讨论】:

  • 会话13/10/20 07:14:4913/10/20 07:15:08 怎么样?它是否计入间隔2020-10-13 07:00:00 - 07:15:002020-10-13 07:15:00 - 07:30:00? IE。开始时间或结束时间是否相关(或两者都相关)?

标签: sql oracle time-series


【解决方案1】:

我使用这个通用函数来解决这样的问题:

FUNCTION MakeInterval(ts IN TIMESTAMP, roundInterval IN INTERVAL DAY TO SECOND) RETURN TIMESTAMP DETERMINISTIC IS
    denom INTEGER;
BEGIN
    IF roundInterval >= INTERVAL '1' HOUR THEN
        denom := EXTRACT(HOUR FROM roundInterval);
        IF MOD(24, denom) <> 0 THEN
            RAISE VALUE_ERROR;
        END IF;
        RETURN TRUNC(ts) + TRUNC(EXTRACT(HOUR FROM ts) / denom) * denom * INTERVAL '1' HOUR;
    ELSIF roundInterval >= INTERVAL '1' MINUTE THEN
        denom := EXTRACT(MINUTE FROM roundInterval);
        IF MOD(60, denom) <> 0 THEN
            RAISE VALUE_ERROR;
        END IF;
        RETURN TRUNC(ts, 'hh') + TRUNC(EXTRACT(MINUTE FROM ts) / denom) * denom * INTERVAL '1' MINUTE;
    ELSE
        denom := EXTRACT(SECOND FROM roundInterval);                
        IF MOD(60, denom) <> 0 THEN
            RAISE VALUE_ERROR;
        END IF;
        RETURN TRUNC(ts, 'mi') + TRUNC(EXTRACT(SECOND FROM ts) / denom) * denom * INTERVAL '1' SECOND;
    END IF;
END MakeInterval;

那么查询会是这样的:

select COUNT(*),
    ZONEID, MACADDRESS, 
    MakeInterval(START_TS, INTERVAL '15' MINUTES) as START_TS,
    MakeInterval(START_TS, INTERVAL '15' MINUTES) + INTERVAL '15' MINUTES as END_TS
from t
GROUP BY MakeInterval(START_TS, INTERVAL '15' MINUTES);

【讨论】:

  • OP 想要每 15 分钟间隔内的分钟数总和,并且每一行可以在多个间隔内(有一个 SJC20-3-NZ-5 行从 07:14:4907:15:08) .
【解决方案2】:

您可以找到最小和最大时间界限(最接近的前 15 分钟间隔),然后使用行生成器在这些界限之间生成 15 分钟间隔,然后使用分区外连接(或 INNER JOIN,如果您不这样做'不想要包含 0 时间的行)并将间隔内的分钟数相加:

WITH bounds ( min_ts, max_ts ) AS (
  SELECT TRUNC( MIN( start_ts ), 'HH' )
         + INTERVAL '15' MINUTE
           * TRUNC(
               (
                 TRUNC( MIN( start_ts ), 'MI' ) - TRUNC( MIN( start_ts ), 'HH' )
               ) * 24 * 4
             ),
         TRUNC( MAX( end_ts ), 'HH' )
         + INTERVAL '15' MINUTE
           * TRUNC(
               (
                 TRUNC( MAX( end_ts ), 'MI' ) - TRUNC( MAX( end_ts ), 'HH' )
               ) * 24 * 4
             )
  FROM   table_name
),
interval_times ( ts ) AS (
  SELECT min_ts + ( LEVEL - 1 ) * INTERVAL '15' MINUTE AS ts
  FROM   bounds
  CONNECT BY min_ts + ( LEVEL - 1 ) * INTERVAL '15' MINUTE <= max_ts
)
SELECT t.zoneid,
       t.macaddress,
       i.ts AS start_ts,
       i.ts + INTERVAL '15' MINUTE AS end_ts,
       SUM(
         COALESCE(
           (
             LEAST( i.ts + INTERVAL '15' MINUTE, t.end_ts )
             - GREATEST( i.ts, t.start_ts )
           ) * 24 * 60,
           0
         )
       ) AS time_mins
FROM   interval_times i
       LEFT OUTER JOIN table_name t
       PARTITION BY ( t.zoneid, t.macaddress )
       ON ( t.start_ts < i.ts + INTERVAL '15' MINUTE AND i.ts < t.end_ts )
GROUP BY
       t.zoneid,
       t.macaddress,
       i.ts
ORDER BY
       i.ts,
       t.macaddress,
       t.zoneid;

您的样本数据:

CREATE TABLE table_name ( ZONEID, MACADDRESS, START_TS, END_TS ) AS
SELECT 'SJC20-3-NZ-4', '00:00:04:be:23:7c', TIMESTAMP '2020-01-13 07:00:30', TIMESTAMP '2020-01-13 07:04:26' FROM DUAL UNION ALL
SELECT 'SJC20-3-NZ-4', '00:00:04:be:23:7c', TIMESTAMP '2020-01-13 07:04:26', TIMESTAMP '2020-01-13 07:04:28' FROM DUAL UNION ALL
SELECT 'SJC20-3-NZ-5', '00:00:04:be:23:7c', TIMESTAMP '2020-01-13 07:04:28', TIMESTAMP '2020-01-13 07:14:49' FROM DUAL UNION ALL
SELECT 'SJC20-3-NZ-5', '00:00:04:be:23:7c', TIMESTAMP '2020-01-13 07:14:49', TIMESTAMP '2020-01-13 07:15:08' FROM DUAL UNION ALL
SELECT 'SJC20-3-NZ-5', '00:00:04:be:23:7c', TIMESTAMP '2020-01-13 07:15:08', TIMESTAMP '2020-01-13 07:16:49' FROM DUAL UNION ALL
SELECT 'SJC20-3-NZ-6', '00:00:04:be:23:7c', TIMESTAMP '2020-01-13 07:16:49', TIMESTAMP '2020-01-13 07:17:17' FROM DUAL UNION ALL
SELECT 'SJC20-3-NZ-6', '00:00:04:be:23:7c', TIMESTAMP '2020-01-13 07:17:17', TIMESTAMP '2020-01-13 07:19:09' FROM DUAL UNION ALL
SELECT 'SJC20-3-NZ-6', '00:00:04:be:23:7c', TIMESTAMP '2020-01-13 07:19:09', TIMESTAMP '2020-01-13 07:19:22' FROM DUAL

输出:

区号 | MAC地址 | START_TS | END_TS | TIME_MINS :----------- | :---------------- | :----------------- | :----------------- | ----------------------------------------------------: SJC20-3-NZ-4 | 00:00:04:be:23:7c | 2020-01-13 07:00:00 | 2020-01-13 07:15:00 | 3.96666666666666666666666666666666666666 SJC20-3-NZ-5 | 00:00:04:be:23:7c | 2020-01-13 07:00:00 | 2020-01-13 07:15:00 | 10.53333333333333333333333333333333333333 SJC20-3-NZ-6 | 00:00:04:be:23:7c | 2020-01-13 07:00:00 | 2020-01-13 07:15:00 | 0 SJC20-3-NZ-4 | 00:00:04:be:23:7c | 2020-01-13 07:15:00 | 2020-01-13 07:30:00 | 0 SJC20-3-NZ-5 | 00:00:04:be:23:7c | 2020-01-13 07:15:00 | 2020-01-13 07:30:00 | 1.81666666666666666666666666666666666666 SJC20-3-NZ-6 | 00:00:04:be:23:7c | 2020-01-13 07:15:00 | 2020-01-13 07:30:00 | 2.550000000000000000000000000000000000001

db小提琴here

【讨论】:

    猜你喜欢
    • 2013-01-23
    • 1970-01-01
    • 2013-08-15
    • 2015-09-28
    • 2018-09-03
    • 2014-07-17
    • 2018-02-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多