我的Oracle数据库中有一些数据源。
如果某个特定的Office_ID已被停用并且它具有特定日期的所有三个客户端(A,B,C),那么我们必须检查所有客户端是否已经消失。如果是,那么我们需要检查所有客户的时间范围是否在10分钟之内。
如果某一办公室每天重复三次,我们宣布办公室已关闭。
以下是一些示例数据:
+-----------+-----------+--------------+--------+
| OFFICE_ID | FAIL_TIME | ACTIVITY_DAY | CLIENT |
| 1002 | 5:39:00 | 23/01/2015 | A |
| 1002 | 17:49:00 | 23/12/2014 | A |
| 1002 | 18:41:57 | 1/5/2014 | B |
| 1002 | 10:32:00 | 1/7/2014 | A |
| 1002 | 10:34:23 | 1/7/2014 | B |
| 1002 | 10:35:03 | 1/7/2014 | C |
| 1002 | 12:08:52 | 1/7/2014 | B |
| 1002 | 12:09:00 | 1/7/2014 | A |
| 1002 | 12:26:10 | 1/7/2014 | B |
| 1002 | 13:31:32 | 1/7/2014 | B |
| 1002 | 15:24:06 | 1/7/2014 | B |
| 1002 | 15:55:06 | 1/7/2014 | C |
+-----------+-----------+--------------+--------+
结果应该是这样的:
1002 10:32:00 A
1002 10:34:23 B
1002 10:35:03 C
任何帮助将不胜感激。我正在寻找SQL查询或PL / SQL过程。
答案 0 :(得分:1)
使用COUNT
analytic function和RANGE BETWEEN INTERVAL '10' MINUTE PRECEDING AND INTERVAL '10' MINUTE FOLLOWING
避免自连接的解决方案:
Oracle 11g R2架构设置:
CREATE TABLE Test ( OFFICE_ID, FAIL_TIME, ACTIVITY_DAY, CLIENT ) AS
SELECT 1002, '5:39:00', '23/01/2015', 'A' FROM DUAL
UNION ALL SELECT 1002, '17:49:00', '23/12/2014', 'A' FROM DUAL
UNION ALL SELECT 1002, '18:41:57', '1/5/2014', 'B' FROM DUAL
UNION ALL SELECT 1002, '10:32:00', '1/7/2014', 'A' FROM DUAL
UNION ALL SELECT 1002, '10:34:23', '1/7/2014', 'B' FROM DUAL
UNION ALL SELECT 1002, '10:35:03', '1/7/2014', 'C' FROM DUAL
UNION ALL SELECT 1002, '12:08:52', '1/7/2014', 'B' FROM DUAL
UNION ALL SELECT 1002, '12:09:00', '1/7/2014', 'A' FROM DUAL
UNION ALL SELECT 1002, '12:26:10', '1/7/2014', 'B' FROM DUAL
UNION ALL SELECT 1002, '13:31:32', '1/7/2014', 'B' FROM DUAL
UNION ALL SELECT 1002, '15:24:06', '1/7/2014', 'B' FROM DUAL
UNION ALL SELECT 1002, '15:55:06', '1/7/2014', 'C' FROM DUAL
查询1 :
WITH Times AS (
SELECT OFFICE_ID,
TO_DATE( ACTIVITY_DAY || ' ' || FAIL_TIME, 'DD/MM/YYYY HH24/MI/SS' ) AS FAIL_DATETIME,
CLIENT
FROM Test
),
Next_Times As (
SELECT OFFICE_ID,
FAIL_DATETIME,
COUNT( CASE CLIENT WHEN 'A' THEN 1 END ) OVER ( PARTITION BY OFFICE_ID ORDER BY FAIL_DATETIME RANGE BETWEEN INTERVAL '10' MINUTE PRECEDING AND INTERVAL '10' MINUTE FOLLOWING ) AS COUNT_A,
COUNT( CASE CLIENT WHEN 'B' THEN 1 END ) OVER ( PARTITION BY OFFICE_ID ORDER BY FAIL_DATETIME RANGE BETWEEN INTERVAL '10' MINUTE PRECEDING AND INTERVAL '10' MINUTE FOLLOWING ) AS COUNT_B,
COUNT( CASE CLIENT WHEN 'C' THEN 1 END ) OVER ( PARTITION BY OFFICE_ID ORDER BY FAIL_DATETIME RANGE BETWEEN INTERVAL '10' MINUTE PRECEDING AND INTERVAL '10' MINUTE FOLLOWING ) AS COUNT_C
FROM Times
)
SELECT OFFICE_ID,
TO_CHAR( FAIL_DATETIME, 'HH24:MI:SS' ) AS FAIL_TIME,
TO_CHAR( FAIL_DATETIME, 'DD/MM/YYYY' ) AS ACTIVITY_DAY
FROM Next_Times
WHERE COUNT_A > 0
AND COUNT_B > 0
AND COUNT_C > 0
ORDER BY FAIL_DATETIME
<强> Results 强>:
| OFFICE_ID | FAIL_TIME | ACTIVITY_DAY |
|-----------|-----------|--------------|
| 1002 | 10:32:00 | 01/07/2014 |
| 1002 | 10:34:23 | 01/07/2014 |
| 1002 | 10:35:03 | 01/07/2014 |
答案 1 :(得分:0)
要识别您可以连接表格的记录三次,如下所示:
SELECT
a.*, b.*, c.*
FROM FailLog a INNER JOIN
FailLog b ON b.OFFICE_ID = A.OFFICE_ID AND
a.CLIENT = 'A' AND
b.CLIENT = 'B' AND
b.ACTIVITY_DAY = a.ACTIVITY_DAY INNER JOIN
FailLog c ON c.OFFICE_ID = A.OFFICE_ID AND
c.CLIENT = 'C' AND
c.ACTIVITY_DAY = a.ACTIVITY_DAY AND
-- need to calculate difference in min here
GREATEST (a.FAIL_TIME, b. FAIL_TIME, c. FAIL_TIME) -
LEAST (a.FAIL_TIME, b. FAIL_TIME, c. FAIL_TIME) <= 10
输出将为您提供一行而不是问题中请求的三行,但这将是故障数据的正确级别,因为所有三个客户端都应该拥有它。
答案 2 :(得分:0)
我们需要的第一件事就是比较FAIL_TIME。由于您还没有发布表结构,我们假设我们正在处理字符串。
Oracle有一些用于投射日期和字符串的简洁内置插件。如果我们连接ACTIVITY_DATE和FAIL_TIME,我们可以将它们转换为DATE数据类型:
to_date(ACTIVITY_DAY||' '||FAIL_TIME, 'dd/mm/yyyy hh24:mi:ss')
我们可以将其转换为表示午夜过后秒数的字符串:
to_char(to_date(ACTIVITY_DAY||' '||FAIL_TIME, 'dd/mm/yyyy hh24:mi:ss'), 'sssss')
然后我们可以将 转换为数字,我们可以在某些算术中使用它来与其他行进行比较;十分钟= 600秒。
接下来我们可以使用子查询分解(WITH子句)。这种语法的一个优点是我们可以将一个子查询的输出传递给另一个子查询,因此我们只需要编写一次这种粗糙的嵌套转换表达式。
with t as
( select OFFICE_ID
, ACTIVITY_DAY
, FAIL_TIME
, to_number(to_char(to_date(ACTIVITY_DAY||' '||FAIL_TIME, 'dd/mm/yyyy hh24:mi:ss'), 'sssss')) FAIL_TIME_SSSSS
, CLIENT
from faillog
)
我们可以使用这个子查询来构建其他子查询,这些子查询将表的行分成每个CLIENT的集合,以便在我们的主查询中使用。
最后,我们可以使用分析COUNT()函数来跟踪每个OFFICE和ACTIVITY_DATE组合中有多少个FAIL_TIME。
count(*) over (partition by a.OFFICE_ID, a.ACTIVITY_DAY)
将所有内容放在一个内联视图中,我们可以测试我们是否可以“宣布办公室已关闭”。
select * from (
with t as ( select OFFICE_ID
, ACTIVITY_DAY
, FAIL_TIME
, to_number(to_char(to_date(ACTIVITY_DAY||' '||FAIL_TIME, 'dd/mm/yyyy hh24:mi:ss'), 'sssss')) FAIL_TIME_SSSSS
, CLIENT
from faillog
)
, a as (select *
from t
where CLIENT = 'A' )
, b as (select *
from t
where CLIENT = 'B' )
, c as (select *
from t
where CLIENT = 'C' )
select a.OFFICE_ID
, a.ACTIVITY_DAY
, a.FAIL_TIME as a_fail_time
, b.FAIL_TIME as b_fail_time
, c.FAIL_TIME as a_fail_time
, count(*) over (partition by a.OFFICE_ID, a.ACTIVITY_DAY) as fail_count
from a
join b on a.OFFICE_ID = b.OFFICE_ID and a.ACTIVITY_DAY = b.ACTIVITY_DAY
join c on a.OFFICE_ID = c.OFFICE_ID and a.ACTIVITY_DAY = c.ACTIVITY_DAY
where a.FAIL_TIME_SSSSS between b.FAIL_TIME_SSSSS - 600 and b.FAIL_TIME_SSSSS + 600
and a.FAIL_TIME_SSSSS between c.FAIL_TIME_SSSSS - 600 and c.FAIL_TIME_SSSSS + 600
and b.FAIL_TIME_SSSSS between a.FAIL_TIME_SSSSS - 600 and a.FAIL_TIME_SSSSS + 600
and b.FAIL_TIME_SSSSS between c.FAIL_TIME_SSSSS - 600 and c.FAIL_TIME_SSSSS + 600
and c.FAIL_TIME_SSSSS between a.FAIL_TIME_SSSSS - 600 and a.FAIL_TIME_SSSSS + 600
and c.FAIL_TIME_SSSSS between b.FAIL_TIME_SSSSS - 600 and b.FAIL_TIME_SSSSS + 600
)
where fail_count >= 3
/
备注强>