Oracle SQL - 隔离孤立数据

时间:2016-06-06 20:27:42

标签: sql oracle

我有一个应用程序可以跟踪文件被“尝试”从一个服务器移动到另一个服务器,以及何时“成功”或“失败”。“尝试”应始终与“成功”或“失败”。但是,我遇到了孤儿的尝试......这意味着没有任何成功或失败的尝试。从another question我问过,我能够隔离被认为是孤儿的 e_ids 。但是,我不想在最终输出中返回“非孤立”传输。请考虑以下示例输出:

enter image description here 例如,在上面的输出中,e_id 000125 在5/23/2016 11:37:09 PM时完成了传输(尝试 - >成功)。我不想看这个。同样,e_id 000672 在5/25/2016 1:28:36 PM时完成了传输(尝试 - >失败)。我也不想看到这个。我想要查看孤立的传输,结果集如下所示:

enter image description here

值得注意的是,所有已完成的传输都在一秒内发生(因此,为什么在第一个样本输出中日期显示为相同,实际上它们相差几毫秒)。

最后,我的查询到目前为止如下

--This query shows all data for all contact_id's known to be an orphan
SELECT * FROM
(
    SELECT
        d.*
    FROM
        (
            SELECT e_id, COUNT(*) AS attempts FROM e_table
            WHERE e_comment LIKE '%attempting%'
            AND e_date >= '23-MAY-2016'
            AND e_date <= '26-MAY-2016'
            GROUP BY e_id
        ) a
        FULL OUTER JOIN
        (
            SELECT e_id, COUNT(*) AS successes FROM e_table
            WHERE e_comment LIKE '%successful%'
            AND e_date >= '23-MAY-2016'
            AND e_date <= '26-MAY-2016'
            GROUP BY e_id
        ) s
            ON s.e_id = a.e_id
        FULL OUTER JOIN
        (
            SELECT e_id, COUNT(*) AS failures FROM e_table
            WHERE e_comment LIKE '%failed%'
            AND e_date >= '23-MAY-2016'
            AND e_date <= '26-MAY-2016'
            GROUP BY e_id
        ) f
            ON f.e_id = COALESCE(a.e_id, s.e_id)
        FULL OUTER JOIN
        (
            SELECT * FROM e_table
            WHERE e_date >= '23-MAY-2016'
            AND e_date <= '26-MAY-2016'
        ) d
           ON a.e_id = d.e_id           
    WHERE
        COALESCE(attempts, 0) <> COALESCE(successes, 0) + COALESCE(failures, 0)
)
MINUS
(
    --This is where I'm stuck. I figure, with a MINUS, I can remove the
    --cases with completed transmissions, thus showing ONLY the orphans.
)   

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:2)

这是一个不需要任何连接的解决方案;相反,它使用LEAD分析函数。

Oracle安装程序

CREATE TABLE e_table ( ce_id, e_id, e_comment, e_date ) AS
SELECT '472', '125', 'is attempting to move',  TIMESTAMP '2016-05-23 09:49:10' FROM DUAL UNION ALL
SELECT '678', '125', 'is attempting to move',  TIMESTAMP '2016-05-23 11:37:09' FROM DUAL UNION ALL
SELECT '724', '125', 'has successfully moved', TIMESTAMP '2016-05-23 11:37:09' FROM DUAL UNION ALL
SELECT '983', '034', 'is attempting to move',  TIMESTAMP '2016-05-24 17:04:35' FROM DUAL UNION ALL
SELECT '643', '672', 'is attempting to move',  TIMESTAMP '2016-05-25 13:28:36' FROM DUAL UNION ALL
SELECT '026', '672', 'failed to move',         TIMESTAMP '2016-05-25 13:28:36' FROM DUAL UNION ALL
SELECT '087', '672', 'is attempting to move',  TIMESTAMP '2016-05-24 18:33:35' FROM DUAL;

<强>查询

SELECT ce_id,
       e_id,
       e_comment,
       e_date
FROM   (
  SELECT e.*,
         LEAD( e_comment )
           OVER ( PARTITION BY e_id
                  ORDER BY e_date,
                           DECODE( e_comment, 'is attempting to move', 1, 2 )
                ) AS next_comment
  FROM   e_table e
)
WHERE  ( next_comment IS NULL OR next_comment = 'is attempting to move' )
AND    e_comment = 'is attempting to move';

<强>输出

CE_ID E_ID E_COMMENT              E_DATE                      
----- ---- ---------------------- -----------------------------
983   034  is attempting to move  2016-05-24 17:04:35.000000000 
472   125  is attempting to move  2016-05-23 09:49:10.000000000 
087   672  is attempting to move  2016-05-24 18:33:35.000000000

答案 1 :(得分:0)

以下查询完成了我的需要。我没有使用原始问题中指定的范围,而是提取“昨天的”数据:

SELECT et.* FROM
(
    SELECT ce_id, e_id FROM e_table et
    WHERE e_comment LIKE ("attempt")
    AND e_date >= TO_DATE(TRUNC(SYSDATE-1))
    AND e_date <= TO_DATE(TRUNC(SYSDATE-1) || ' 23:59:59', 'DD-MON-YY HH24:MI:SS')
    AND NOT EXISTS
    (
        SELECT ce_id, e_id FROM e_table ett
        WHERE e_comment LIKE ("success") OR e_comment LIKE ("failure")
        AND et.e_id = ett.e_id
        AND ett.ce_id > et.ce_id
    ) 
) orphans, e_table et
WHERE orphans.ce_id = et.ce_id
AND orphans.e_id = et.e_id
ORDER BY et.ce_id ASC;