Oracle SQL - 有效计算并发电话呼叫数

时间:2018-04-09 11:09:13

标签: sql oracle

我知道这个问题基本上是我提出的一个较旧问题的重复,但是自从我提出这个问题后,有很多事情发生了变化,所以我想我会问一个关于它的新问题。

我有一个表格,其中包含电话记录,其中包含以下字段:

 END: Holds the timestamp of when a call ended - Data Type: DATE
 LINE: Holds the phone line that was used for a call - Data Type: NUMBER
 CALLDURATION: Holds the duration of a call in seconds - Data Type: NUMBER

该表包含以下条目:

END                    LINE                CALLDURATION
---------------------- ------------------- -----------------------
25/01/2012 14:05:10    6                   65
25/01/2012 14:08:51    7                   1142
25/01/2012 14:20:36    5                   860

我需要创建一个查询,根据该表中的数据返回并发电话的数量。查询应以不同的间隔计算该数字。我的意思是,只要调用开始或结束,查询结果应该只包含一个新条目。只要并发电话呼叫数保持不变,输出中就不应有任何其他条目。

为了更清楚,这里是一个例子,查询应该根据上一个表中的示例条目返回:

TIMESTAMP              LINE  CALLDURATION  STATUS  CURRENTLYUSEDLINES          
---------------------- ----- ------------- ------- -------------------
25/01/2012 13:49:49    7     1142          1       1
25/01/2012 14:04:05    6     65            1       2
25/01/2012 14:05:10    6     65            -1      1
25/01/2012 14:06:16    5     860           1       2
25/01/2012 14:08:51    7     1142          -1      1
25/01/2012 14:20:36    5     860           -1      0

我从一位同事那里得到了以下示例查询,但不幸的是我并不完全理解它并且它也不能完全正常工作,因为对于持续时间为0秒的调用,它有时会有" -1&# 34;在CURRENTLYUSEDLINES列中:

SELECT COALESCE (SUM (STATUS) OVER (ORDER BY END ROWS BETWEEN UNBOUNDED PRECEDING AND 0 PRECEDING), 0) CURRENTLYUSEDLINES
    FROM (SELECT END - CALLDURATION / 86400 AS TIMESTAMP,
                 LINE,
                 CALLDURATION,
                 1 AS STATUS
            FROM t_calls
          UNION ALL
          SELECT END,
                 LINE,
                 CALLDURATION,
                 -1 AS STATUS
            FROM t_calls) t
ORDER BY 1;

现在我应该像在示例中那样使查询工作,但我不知道该怎么做。

有人可以帮我解决这个问题,或者至少解释一下这个问题,以便我自己尝试修复它吗?

2 个答案:

答案 0 :(得分:1)

我认为这可以解决您的问题:

SELECT TIMESTAMP,
       SUM(SUM(STATUS)) OVER (ORDER BY TIMESTAMP) as CURRENTLYUSEDLINES
FROM ((SELECT END - CALLDURATION / (24*60*60) AS TIMESTAMP,
              COUNT(*) AS STATUS
       FROM t_calls
       GROUP BY END - CALLDURATION / (24*60*60)
      ) UNION ALL
      (SELECT END, - COUNT(*)  AS STATUS
       FROM t_calls
       GROUP BY END
      )
     ) t
GROUP BY TIMESTAMP
ORDER BY 1;

这是您查询的略微简化。但是通过完成所有聚合,您应该获得0 s,但不是负值。

您正在获得负值,因为"结束"在开始之前正在处理呼叫。这样可以同时完成所有工作",因为每个时间戳只有一行。

答案 1 :(得分:0)

您可以使用UNPIVOT(使用与my answer here类似的技巧):

SQL Fiddle

Oracle 11g R2架构设置

CREATE TABLE table_name ( END, LINE, CALLDURATION ) AS
  SELECT CAST( TIMESTAMP '2012-01-25 14:05:10' AS DATE ), 6, 65 FROM DUAL UNION ALL
  SELECT CAST( TIMESTAMP '2012-01-25 14:08:51' AS DATE ), 7, 1142 FROM DUAL UNION ALL
  SELECT CAST( TIMESTAMP '2012-01-25 14:20:36' AS DATE ), 5, 860 FROM DUAL;

查询1

SELECT p.*,
       SUM( status ) OVER ( ORDER BY dt, status DESC ) AS currentlyusedlines
FROM   (
  SELECT end - callduration / 86400 As dt,
         t.*
  FROM   table_name t
)
UNPIVOT( dt FOR status IN ( dt As 1, end AS -1 ) ) p

<强> Results

| LINE | CALLDURATION | STATUS |                   DT | CURRENTLYUSEDLINES |
|------|--------------|--------|----------------------|--------------------|
|    7 |         1142 |      1 | 2012-01-25T13:49:49Z |                  1 |
|    6 |           65 |      1 | 2012-01-25T14:04:05Z |                  2 |
|    6 |           65 |     -1 | 2012-01-25T14:05:10Z |                  1 |
|    5 |          860 |      1 | 2012-01-25T14:06:16Z |                  2 |
|    7 |         1142 |     -1 | 2012-01-25T14:08:51Z |                  1 |
|    5 |          860 |     -1 | 2012-01-25T14:20:36Z |                  0 |