0

I am trying to collect an array of revisions numbers.
I will use to delete records in multiple audit tables.
So I wrote a plsql to collect that array and to run delete on other tables based on condition using that array

declare 
  type NumberArray is table of number index by binary_integer;
  revisions NumberArray;
Begin
  select rev bulk collect into revisions from (
    select t.rev, row_number() over (partition by 
        column1,
        column2
        order by column3) rn
    from table1 t)
  where rn <> 1;

  dbms_output.put_line(revisions.count || ' records found from table2 to be deleted');
  delete from table2 where rev in (revisions);
  dbms_output.put_line('deleted from table2');

I am getting

 PLS-00382: expression is of wrong type
 06550. 00000 -  "line %s, column %s:\n%s"
 *Cause:    Usually a PL/SQL compilation error.

Datatype of rev is number in table1.

3
  • Why PL/SQL when you could do it simply in SQL? Commented Jan 13, 2015 at 8:04
  • data is very huge.. i want to running time Commented Jan 13, 2015 at 8:46
  • If data is huge, then context switching will be huge, PL/SQL will be slower, much slower than SQL. Commented Jan 13, 2015 at 8:51

3 Answers 3

7

This is a good candidate for FORALL statement

declare 
  type NumberArray is table of number(10) index by binary_integer;
  revisions NumberArray;
Begin
  select rev bulk collect into revisions from (
    select t.rev, row_number() over (partition by 
        column1,
        column2
        order by column3) rn
    from table1 t)
  where rn <> 1;

  dbms_output.put_line(revisions.count || ' records found from table2 to be deleted');
  forall i in revisions.first .. revisions.last
       delete from table2 where rev = revisions(i);
  dbms_output.put_line('deleted from table2');
End;

But if you still insist on using IN condition, you have to define your type at schema level:

create type NumberArray as table of number;

and then use it like this

declare 
  revisions NumberArray;
Begin
  select rev bulk collect into revisions from (
    select t.rev, row_number() over (partition by 
        column1,
        column2
        order by column3) rn
    from table1 t)
  where rn <> 1;

  dbms_output.put_line(revisions.count || ' records found from table2 to be deleted');
  delete from table2 where rev in (select column_value from table(revisions));
  dbms_output.put_line('deleted from table2');
End;
Sign up to request clarification or add additional context in comments.

Comments

3

It must be this one:

delete from table2 where rev MEMBER OF revisions;

or 

delete from table2 where rev =ANY (SELECT COLUMN_VALUE FROM TABLE(revisions));

or 

forall i in revisions.FIRST..revisions.LAST
delete from table2 where rev = revisions(i);

or 

delete from table2 where rev =ANY (
select rev 
from (
    select t.rev, row_number() over (partition by 
        column1,
        column2
        order by column3) rn
    from table1 t)
  where rn <> 1
);

or (not the preferred way of doing it)

for i in revisions.FIRST..revisions.LAST LOOP
   delete from table2 where rev = revisions(i);
END LOOP;

As already written by Marcin Wroblewski, the nested table has to be created on Schema level.

Comments

1

And why would you do it in PL/SQL when it could be done in plain SQL? You are unnecessarily introducing context switching between both the engines.

All that PL/SQL code is nothing but a simple DELETE statement -

DELETE FROM table2 WHERE rev IN(
   SELECT rev FROM(
      select t.rev, row_number() over (partition by 
              column1,
              column2
              order by column3) rn
      from table1 t)
  where rn <> 1
);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.