ORACLE按字符串和日期匹配并选择两行

时间:2018-01-31 15:30:37

标签: sql oracle

在我的oracle数据库中,我得到了一个包含多行存储事件信息消息的表。

每个事件都是特定的事件类型。此外,每个事件都有一个列值“OPEN”或“CLOSED”,表示事件消息是打开还是关闭消息。

现在我需要确定所有“OPEN”消息并获得相应的“CLOSED”。以我的表为例:

    +----+----------+-----------+-------------------+-----------------------------+--------+
| ID | SENDERID | EventType | EventDescription  | Date                        | Status |
+----+----------+-----------+-------------------+-----------------------------+--------+
| 1  | 111      | EventTyp2 | Something happend | 27.03.17 12:56:10,000000000 | CLOSED |
+----+----------+-----------+-------------------+-----------------------------+--------+
| 2  | 111      | EventTyp1 | Something happend | 20.03.17 00:12:29,666000000 | CLOSED |
+----+----------+-----------+-------------------+-----------------------------+--------+
| 3  | 111      | EventTyp2 | Something happend | 19.03.17 00:12:31,255000000 | OPEN   |
+----+----------+-----------+-------------------+-----------------------------+--------+
| 4  | 222      | EventTyp2 | Something happend | 19.03.17 00:12:31,255000000 | CLOSED |
+----+----------+-----------+-------------------+-----------------------------+--------+
| 5  | 111      | EventTyp1 | Something happend | 17.03.17 11:32:42,452000000 | OPEN   |
+----+----------+-----------+-------------------+-----------------------------+--------+
| 6  | 222      | EventTyp2 | Something happend | 17.03.17 11:32:36,185000000 | OPEN   |
+----+----------+-----------+-------------------+-----------------------------+--------+

有没有办法获得一个结果,该结果将开启和关闭日期一起返回事件类型和描述?

我不知道如何说“搜索包含相同EventTyp和'最近'日期的CLOSING行,因为这必须是结束事件消息'。

修改

结果应该与以下示例相同

+----+-----------+-----------+-------------------+-----------------------------+-----------------------------+
| ID | Sender ID | EventType | EventDescription  | Date Open                   | Date Closed                 |
+----+-----------+-----------+-------------------+-----------------------------+-----------------------------+
| 1  | 111       | EventTyp2 | Something happend | 19.03.17 00:12:31,255000000 | 27.03.17 12:56:10,000000000 |
+----+-----------+-----------+-------------------+-----------------------------+-----------------------------+
| 2  | 111       | EventTyp1 | Something happend | 17.03.17 11:32:42,452000000 | 20.03.17 00:12:29,666000000 |
+----+-----------+-----------+-------------------+-----------------------------+-----------------------------+
| 3  | 222       | EventTyp2 | Something happend | 17.03.17 11:32:36,185000000 | 19.03.17 00:12:31,255000000 |
+----+-----------+-----------+-------------------+-----------------------------+-----------------------------+

我已经尝试过以下操作,但是你可以假设我为一个“OPEN”行获得所有匹配的“CLOSED”行。 (我已对查询进行了匿名处理)

WITH EventOpen AS
(
SELECT 
  event.ID,
  event.SENDERID,
  event.DATE,
  event.STATUS,
  event.EVENTTYPID,
  event.EVENTDESCRIPTION
FROM
  EVENTTABLE event 
WHERE
  event.STATUS = 'OPEN'
),
EventClose AS
(
SELECT 
  event.ID,
  event.SENDERID,
  event.DATE,
  event.STATUS,
  event.EVENTTYPID,
  event.EVENTDESCRIPTION
FROM
  EVENTTABLE event
WHERE
  event.STATUS = 'CLOSED'
),

SELECT 
  eo.ID,
  eo.SENDERID
  eo.EVENTDESCRIPTION
  eo.EVENTTYPID
  eo.DATE AS OPENEDAT,  
  ec.DATE AS CLOSEDAD,
FROM 
  EventOpen eo
LEFT OUTER JOIN EventClose ec 
ON eo.EVENTTYPID = ec.EVENTTYPID 
AND eo.SENDERID = ec.SENDERID
AND eo.ID < ec.ID AND (eo.DATE < ec.DATE)

EDIT2: 感谢匿名,我错过了一个重要的专栏:senderid。每个事件都有一个特定的源,由senderid

定义

3 个答案:

答案 0 :(得分:1)

使用lead()分析函数来匹配OPEN和CLOSE事件:

select *
from (
    select
        ev.EVENTTYPID,
        ev.SENDERID,
        ev.DATE open_date,
        lead(ev.DATE) over 
            (partition by ev.EVENTTYPID, ev.SENDERID order by ev.DATE) close_date,
        ev.EVENTDESCRIPTION open_description,       
        lead(ev.EVENTDESCRIPTION) over 
            (partition by ev.EVENTTYPID, ev.SENDERID order by ev.DATE) close_description,
        ev.STATUS
    from EVENTTABLE ev
    ) 
where STATUS = 'OPEN'
order by open_date

如果您不想查询尚未关闭的事件,请添加

and close_date is not null

到外where子句。

答案 1 :(得分:1)

@ fen1x的优秀解决方案有一点变化,涵盖重复的OPEN事件。

此外,在state上检查并测试了潜在客户CLOSE,即处理已关闭=或NULL(即处理仍在进行中)。国家OPEN的重复案例受到了压制。

select 
EVENTTYPE, SENDERID, OPEN_DATE, CLOSE_DATE, OPEN_DESCRIPTION, CLOSE_DESCRIPTION, NEXT_STATUS
from (
    select
        ev.EVENTTYPE,
        ev.SENDERID,
        ev.trans_d open_date,
        lead(ev.trans_d) over 
            (partition by ev.EVENTTYPE, ev.SENDERID order by ev.trans_d) close_date ,
        -- check for duplicated close
        lead(ev.status) over 
            (partition by ev.EVENTTYPE, ev.SENDERID order by ev.trans_d) next_status,
        ev.EVENTDESCRIPTION open_description,       
        lead(ev.EVENTDESCRIPTION) over 
            (partition by ev.EVENTTYPE, ev.SENDERID order by ev.trans_d) close_description, 
        ev.STATUS
    from tab ev
    ) 
where STATUS = 'OPEN' and  (NEXT_STATUS = 'CLOSED' or NEXT_STATUS is NULL)
order by open_date

请注意,这是简单的清洁;如果EVENTTYPESENDERID内有重复,则最后OPEN与第一个CLOSE相关联 - 所有其他重复事件都将被忽略。

答案 2 :(得分:0)

这个在SQL SERVER上运行,在ORACLE中应该也很有用

select position = DENSE_RANK () over (order by EventType, SenderID, Date),*
into #t
from EVENTTABLE event 
where Status ='OPEN'
order by EventType, SenderID, Date

select t.*, CloseDate = ev.DatE
from #t t
    left join EVENTTABLE ev on
        ev.EventType = t.EventType and 
        ev.SenderID = t.SenderID and
        ev.Status = 'OUT' and
        ev.Date > t.Date and
        ev.Date < (select Date from #t where position = t.position+1)