Oracle SQL - 如何按顺序遍历此结果集以删除某些记录?

时间:2016-06-17 18:24:06

标签: sql oracle loops

我的当前输出如下图所示。我突出显示了我想删除的记录。

Current Output

我主要是C#开发人员,所以我的“伪逻辑”来获得我想要的结果如下:

List<int> resultSet = new List<int>();

for(int i = 1; i < table.Length; i++)
{
    if((c_id[i] == c_id[i-1])&&
       (sub_id[i] < sub_id[i-1]))
    {
        resultSet.Remove(contact_event_id[i]);
        resultSet.Remove(contact_event_id[i-1]);
    }
}

基本上,我想要做的是从结果集中删除c_id“配对”的记录。如果出现以下情况,则会将两条记录视为

  • 记录i和记录i-1有相同的c_id
  • 记录我的 sub_id小于记录i-1

一些重要的注意事项:

  1. 我只有读访问到这个数据库/表。
  2. ce_id是此表的主键,我们称之为 e_table
  3. 不要依赖e_date进行订购......请使用ce_id。
  4. 我到目前为止的SQL是在下面。注意子句中的“...”;这是为了使实现尽可能简单。除非真的需要,否则这项任务涉及的逻辑更多,不值得进入。

    SELECT * FROM
    (
        SELECT * FROM e_table
        WHERE 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 sub_id IN(2, 1)
    ) ce
    WHERE ce.c_id IN
    (
        select c_id
        from e_table
        where e_date >= TO_DATE(TRUNC(SYSDATE-1))
        AND e_date <= TO_DATE(TRUNC(SYSDATE-1) || ' 23:59:59', 'DD-MON-YY HH24:MI:SS')
        group by c_id
        having ...
    )
    ORDER BY ce_id ASC;
    

    非常感谢任何帮助。如果需要任何详细说明,请告诉我。

    编辑#1,如评论中MT0所指出的那样: 考虑以下记录集: enter image description here

    请注意,根据我目前提出的逻辑,两个中间记录被认为是对。他们应该被删除;毫无疑问。但是,事后看到如何移除剩余的两行也符合乍一看的要求?它们不应,因为它们在原始输出中不相邻。在这种情况下,我认为毕竟必须使用e_date。但是,重要的是要注意这些对的时间虽然看似相同,但最多可相差一秒。无论如何,仍然需要使用ce_id进行排序,因为按日期排序会导致sub_id不恰当地切换位置。

    编辑#2:

    上面的图片只是为了表明实现应该在我的查询生成的记录集中进行一次传递。 实际上,sub_id连续两个连续的1是不可能的,正如整篇评论中所解释的那样。

    编辑#3

    MT0要求的DML:

    CREATE TABLE e_table (
      ce_id  INT,
      c_id   CHAR(3),
      sub_id INT
    );
    
    INSERT INTO e_table
    SELECT 1, '421', 2 FROM DUAL UNION ALL
    SELECT 2, '421', 2 FROM DUAL UNION ALL
    SELECT 3, '359', 2 FROM DUAL UNION ALL
    SELECT 4, '220', 2 FROM DUAL UNION ALL
    SELECT 5, '288', 2 FROM DUAL UNION ALL
    SELECT 6, '402', 2 FROM DUAL UNION ALL
    SELECT 7, '348', 2 FROM DUAL UNION ALL
    SELECT 8, '402', 2 FROM DUAL UNION ALL
    SELECT 9, '402', 1 FROM DUAL UNION ALL
    SELECT 10, '062', 2 FROM DUAL UNION ALL
    SELECT 11, '062', 1 FROM DUAL UNION ALL
    SELECT 12, '062', 2 FROM DUAL UNION ALL
    SELECT 13, '029', 2 FROM DUAL UNION ALL
    SELECT 14, '325', 2 FROM DUAL UNION ALL
    SELECT 15, '549', 2 FROM DUAL UNION ALL
    SELECT 16, '278', 2 FROM DUAL UNION ALL
    SELECT 17, '852', 2 FROM DUAL UNION ALL
    SELECT 18, '490', 2 FROM DUAL UNION ALL
    SELECT 19, '490', 1 FROM DUAL UNION ALL
    SELECT 20, '490', 2 FROM DUAL UNION ALL
    SELECT 21, '490', 1 FROM DUAL UNION ALL
    SELECT 22, '490', 2 FROM DUAL UNION ALL
    SELECT 23, '781', 2 FROM DUAL UNION ALL
    SELECT 24, '019', 2 FROM DUAL UNION ALL
    SELECT 25, '019', 1 FROM DUAL UNION ALL
    SELECT 26, '082', 2 FROM DUAL UNION ALL
    SELECT 27, '082', 1 FROM DUAL UNION ALL
    SELECT 28, '082', 2 FROM DUAL UNION ALL
    SELECT 29, '990', 2 FROM DUAL UNION ALL
    SELECT 30, '019', 2 FROM DUAL UNION ALL
    SELECT 31, '041', 2 FROM DUAL;
    

3 个答案:

答案 0 :(得分:1)

Oracle安装程序

CREATE TABLE e_table (
  ce_id  INT,
  c_id   CHAR(3),
  sub_id INT
);

INSERT INTO e_table
SELECT  1, '421', 2 FROM DUAL UNION ALL
SELECT  2, '421', 2 FROM DUAL UNION ALL
SELECT  3, '359', 2 FROM DUAL UNION ALL
SELECT  4, '220', 2 FROM DUAL UNION ALL
SELECT  5, '288', 2 FROM DUAL UNION ALL
SELECT  6, '402', 2 FROM DUAL UNION ALL
SELECT  7, '348', 2 FROM DUAL UNION ALL
SELECT  8, '402', 2 FROM DUAL UNION ALL
SELECT  9, '402', 1 FROM DUAL UNION ALL
SELECT 10, '152', 2 FROM DUAL UNION ALL
SELECT 11, '062', 2 FROM DUAL UNION ALL
SELECT 12, '062', 1 FROM DUAL UNION ALL
SELECT 13, '062', 2 FROM DUAL UNION ALL
SELECT 14, '029', 2 FROM DUAL UNION ALL
SELECT 15, '062', 1 FROM DUAL UNION ALL
SELECT 16, '325', 2 FROM DUAL UNION ALL
SELECT 17, '549', 2 FROM DUAL UNION ALL
SELECT 18, '001', 2 FROM DUAL UNION ALL
SELECT 19, '002', 2 FROM DUAL UNION ALL
SELECT 20, '002', 1 FROM DUAL UNION ALL
SELECT 21, '001', 1 FROM DUAL UNION ALL
SELECT 22, '001', 2 FROM DUAL;

<强>查询

SELECT *
FROM (
  SELECT e.*,
         CASE WHEN (   LEAD( c_id   ) OVER ( ORDER BY ce_id ) = c_id
                   AND LEAD( sub_id ) OVER ( ORDER BY ce_id ) < sub_id )
                OR (   LAG( c_id    ) OVER ( ORDER BY ce_id ) = c_id
                   AND LAG( sub_id  ) OVER ( ORDER BY ce_id ) > sub_id )
              THEN 1
              ELSE 0
              END AS to_delete
  FROM   e_table e
)
WHERE to_delete = 0;

<强>输出

(第8,9,11,12,19和20行已删除。)

     CE_ID C_ID     SUB_ID  TO_DELETE
---------- ---- ---------- ----------
         1 421           2          0 
         2 421           2          0 
         3 359           2          0 
         4 220           2          0 
         5 288           2          0 
         6 402           2          0 
         7 348           2          0 
        10 152           2          0 
        13 062           2          0 
        14 029           2          0 
        15 062           1          0 
        16 325           2          0 
        17 549           2          0 
        18 001           2          0 
        21 001           1          0 
        22 001           2          0 

查询2

SELECT *
FROM (
  SELECT e.*,
         CASE WHEN (   LEAD( c_id   ) OVER ( PARTITION BY c_id ORDER BY ce_id ) = c_id
                   AND LEAD( sub_id ) OVER ( PARTITION BY c_id ORDER BY ce_id ) < sub_id )
                OR (   LAG( c_id    ) OVER ( PARTITION BY c_id ORDER BY ce_id ) = c_id
                   AND LAG( sub_id  ) OVER ( PARTITION BY c_id ORDER BY ce_id ) > sub_id )
              THEN 1
              ELSE 0
              END AS to_delete
  FROM   e_table e
)
WHERE to_delete = 0
ORDER BY ce_id;

<强>输出

(第8,9,11,12,13,15,18,19,20和21行被移除。)

     CE_ID C_ID     SUB_ID  TO_DELETE
---------- ---- ---------- ----------
         1 421           2          0 
         2 421           2          0 
         3 359           2          0 
         4 220           2          0 
         5 288           2          0 
         6 402           2          0 
         7 348           2          0 
        10 152           2          0 
        14 029           2          0 
        16 325           2          0 
        17 549           2          0 
        22 001           2          0 

答案 1 :(得分:1)

计算ce_i​​d排序的每个c_id的行号。

然后加入上一行并检查sub_id值是否为&gt;或者&lt;。

由于自联接使用union all从两个表中获取ce_id并从输出中排除这些行。

with x as (
select t.*,row_number() over(partition by c_id order by ce_id) rn from t
)
select * from t 
where ce_id not in (    
select x1.ce_id
from x x1
join x x2 on x1.c_id = x2.c_id and x1.rn = x2.rn-1
where x1.sub_id > x2.sub_id
union all
select x2.ce_id
from x x1
join x x2 on x1.c_id = x2.c_id and x1.rn = x2.rn-1
where x1.sub_id > x2.sub_id
)

<强> Sample Demo

编辑:要将OP的当前查询包含为cte并使用此答案获取结果,

with t as (/*your query here*/)
, x as (
select t.*,row_number() over(partition by c_id order by ce_id) rn from t
)
select * from t 
where ce_id not in (    
select x1.ce_id
from x x1
join x x2 on x1.c_id = x2.c_id and x1.rn = x2.rn-1
where x1.sub_id > x2.sub_id
union all
select x2.ce_id
from x x1
join x x2 on x1.c_id = x2.c_id and x1.rn = x2.rn-1
where x1.sub_id > x2.sub_id
)

答案 2 :(得分:0)

您希望过滤掉具有sub_id两个值的记录。这表明使用分析函数:

select e.*
from (select e.*,
             count(distinct sub_id) over (partition by c_id) as numcid
      from e_table e
     ) e
where numcid = 1;

此外,您的示例代码中包含日期逻辑,但问题根本没有提及。

如果以上不是正确的逻辑,我非常确定分析函数可以做你想要的。

编辑:

如果你只是在找一个&#34; 1&#34;在&#34; 2&#34;之后发生,然后使用条件聚合:

select e.c_id
from (select e.c_id,
             min(case when sub_id = 1 then e_date end) as sub1_date,
             min(case when sub_id = 2 then e_date end) as sub2_date
      from e_table e
     ) e
where sub1_date > sub2_date;

您可以随意修改此内容以获取原始行。