Oracle顺序操作

时间:2014-02-17 17:50:31

标签: oracle plsql

我有一个数据表详细说明父表上行的操作顺序,其中列ID是该外键。列SEQ是这些动作发生的顺序,ACTION是发生的动作。

ID          SEQ ACTION
12345.00    2   SUSPEND
12345.00    3   CLEAR
12345.00    4   SUSPEND
12345.00    6   CLEAR
12345.00    7   SUSPEND
12345.00    8   RESUME
12345.00    9   SUSPEND
12345.00    10  RESUME
12345.00    11  CLEAR

我试图以这样一种方式呈现数据,即我可以识别未清除的SUSPEND和RESUME操作。在这种情况下,我的结果将如下所示;

12345.00    7   SUSPEND    8    RESUME
12345.00    9   SUSPEND

这是因为;

  CLEAR行动3删除了

SUSPEND行动2.

     CLEAR行动6删除了

SUSPEND行动4。

     

清除行动9删除了RESUME动作8。

ACTION列可以在序列中包含其他操作,因此为了清楚起见,我删除了这些操作。

如果CLEAR将继续操作,则清除操作。

很抱歉,如果这令人困惑。我无法改变架构!

我试图简化问题;

ID          SEQ ACTION
12345.00    2   SUSPEND
12345.00    3   RESUME
12345.00    4   CLEAR
12345.00    5   RESUME
12345.00    6   SUSPEND

结果应如下所示;

12345.00    2   SUSPEND   5 RESUME
12345.00    6   SUSPEND

我尝试了几种方法,但我无法想象如何停止包含3号的RESUME。

4 个答案:

答案 0 :(得分:5)

尝试:

SELECT *
FROM (
   SELECT t.*,
          lead( SEQ ) over ( partition by id order by seq ) next_seq,
          lead( action ) over ( partition by id order by seq ) next_action
   FROM table1 T
)
WHERE action = 'SUSPEND'
  AND next_action <> 'CLEAR'

演示:http://sqlfiddle.com/#!4/5ea45/8

答案 1 :(得分:3)

我尝试从 kordirko 的sqlfiddle,以避免构建相同的架构...抱歉偷了。

在此处查看我的尝试:http://sqlfiddle.com/#!4/5ea45/22

select *
from (select id,
             seq,
             min(case when action != 'SUSPEND' then seq end) over (partition by id order by seq rows between current row and unbounded following) nxt
      from (select t.*,
                   lead(action) over (partition by id order by seq) nxt
            from table1 t)
      where nxt != 'CLEAR'
        and action != 'CLEAR')
where (seq != nxt or nxt is null)

这个想法是:

  1. 仅采取未清除且不自行“清除”的行为
  2. 通过仅查看未来并获得最低限度
  3. ,找出下一步“恢复”的行动
  4. 过滤结果以排除“当前行”
  5. 唯一要做的就是添加非常简单的动作名称,因为每个第一个动作都是“SUSPEND”,第二个动作是非空的“RESUME”。我猜你可以随心所欲地做到这一点:)

答案 2 :(得分:3)

行。现在我从kordirko窃取小提琴,从simon偷取概念,然后按照我的方式做饭。

CREATE TABLE TABLE1
(
   "ID"       INT,
   "SEQ"      INT,
   "ACTION"   VARCHAR2 ( 7 )
);

INSERT ALL
INTO   TABLE1 ( "ID", "SEQ", "ACTION" )
VALUES ( 12345.00, 2, 'SUSPEND' )
INTO   TABLE1 ( "ID", "SEQ", "ACTION" )
VALUES ( 12345.00, 3, 'RESUME' )
INTO   TABLE1 ( "ID", "SEQ", "ACTION" )
VALUES ( 12345.00, 4, 'CLEAR' )
INTO   TABLE1 ( "ID", "SEQ", "ACTION" )
VALUES ( 12345.00, 5, 'RESUME' )
INTO   TABLE1 ( "ID", "SEQ", "ACTION" )
VALUES ( 12345.00, 6, 'SUSPEND' )
   SELECT * FROM DUAL;

所以我从你的问题中理解的是,它最初没有正确解释。但第二个预期的结果就是诀窍。 (我可能还是错了)

WITH AFTER_CHECK
     AS (SELECT T.ID,
                T.SEQ,
                T.ACTION,
                CASE
                   WHEN ACTION = 'CLEAR'
                   THEN
                      1
                   WHEN LEAD ( ACTION ) OVER (PARTITION BY ID ORDER BY SEQ) =
                           'CLEAR'
                   THEN
                      1
                   ELSE
                      0
                END
                   AS IGNORE_CURRENT
         FROM   TABLE1 T)
SELECT *
FROM   (SELECT T.ID,
               T.SEQ,
               T.ACTION,
               LEAD ( SEQ ) OVER (PARTITION BY ID ORDER BY SEQ) NEXT_SEQ,
               LEAD ( ACTION ) OVER (PARTITION BY ID ORDER BY SEQ)
                  NEXT_ACTION
        FROM   AFTER_CHECK T
        WHERE  IGNORE_CURRENT = 0)
WHERE  ACTION = 'SUSPEND';

<强>输出:

12345   2   SUSPEND 5   RESUME
12345   6   SUSPEND     

我所做的是分配一个标志来检查设置为忽略的连续动作,如果它们有一个名为CLEAR的ACTION或一个名为CLEAR的NEXT ACTION。然后我使用kordirko的LEAD函数片段来完成所需的ACTION过滤器。

查看小提琴here

答案 3 :(得分:2)

kordirkos解决方案的这个修改版本应该有效:

SELECT *
FROM (
   SELECT t.*,
          lead( SEQ ) over ( partition by id order by seq ) next_seq,
          lead( action ) over ( partition by id order by seq ) next_action
   FROM table1 T
)
WHERE action in ('SUSPEND', 'RESUME')
  AND (next_action <> 'CLEAR' or next_action is null)