vijay
vijay

Reputation: 33

Conditional delete in oracle using sql or plsql

We have an oracle table x and we have values in it in a following manner

num1  dt        cd
1   24-06-2017  3
1   24-06-2017  4
2   24-06-2017  1
2   24-06-2017  2
2   24-06-2017  4
2   25-06-2017  3
2   25-06-2017  4

Now I have to delete duplicate data from this table using num1,dt , if num1 and dt have any other value instead of 4 then it should exist in table and cd=4 should be deleted. Here in below condition 3 or any other value should exist but it should not be 4

1   24-06-2017  3
1   24-06-2017  4

Now here 4 should be deleted completely for 2 , 24/06/2017 and only 1 rows of each field should exist in the table ie :2 24/06/2017 1 and 2 24/06/2017 2 should exist.

2   24-06-2017  1
2   24-06-2017  2
2   24-06-2017  4

Now in third case if we dont have any other value except 4 for num1 and date then we should have only 1 row of 4 for these dates.

3   26-06-2017  4
3   26-06-2017  4

Please provide solution for this, help will be appreciated.

Upvotes: 2

Views: 3012

Answers (2)

Gordon Linoff
Gordon Linoff

Reputation: 1271141

Oracle conveniently has rowid, which can really help with this. Here is an approach that uses rowid:

delete from t
    where t.rowid <> (select max(rowid) keep (dense_rank first
                                              order by (case when cd = 4 then 2 else 1 end)
                                             )
                      from t
                      where t2.num1 = t.num1 and t2.date = t.date
                     );

This will keep exactly one row per num1/date comparison.

If you are using Oracle 12C+, then a more intuitive form of this query is:

delete from t
    where t.rowid <> (select rowid
                      from t
                      where t2.num1 = t.num1 and t2.date = t.date
                      order by (case when cd = 4 then 2 else 1 end)
                      fetch first 1 row only
                     );

This doesn't work in earlier versions because fetching one row requires an additional subquery -- and that subquery cannot be correlated with the outer query.

Upvotes: 2

fhossfel
fhossfel

Reputation: 2191

If I get your question right it might work like this:

DELETE FROM table
WHERE (num1, dt, ct) IN (SELECT num1, dt, 4
                         FROM table
                         GROUP BY num1, dt
                         HAVING MAX(ct) != 4
                             OR MIN(ct) != 4)
  OR ((num, dt, ct) IN (SELECT num1, dt, MAX(ct)
                FROM table
                GROUP BY num1, dt
                HAVING MAX(ct) = 4
                   AND MIN(ct) = 4)
      AND rowid NOT IN (SELECT MIN(rowid)
                        FROM table
                        GROUP BY num1, dt
                        HAVING MAX(ct) = 4
                           AND MIN(ct) = 4))

Upvotes: 2

Related Questions