Home » SQL & PL/SQL » SQL & PL/SQL » How do I loop within a select statement anspass in parameters?
How do I loop within a select statement anspass in parameters? [message #6875] Fri, 09 May 2003 10:23 Go to next message
Jennifer
Messages: 20
Registered: September 1999
Junior Member
Hi! I want to update my records to null (which is currently working) and then delete the row of records where all the fields except the primary key are null. How do I go about coding it? Please help... Thanks
Below is my code. The logic is there but I just don;t know how to should code it. The first part was workign but I do not know how to go about looping the record for the second part which begins with 'for v_tables in c_tables loop'. How do I move the next data in the cursor like a recordset using .next??

create or replace procedure scheduledelete is
cursor c_tables is
Select distinct tablename from retentionschedule where disposalaction = 'Delete' and disposaldate < sysdate;
cursor c_tempo is
select * from retentionschedule where disposalaction = 'Delete' and disposaldate < sysdate;
begin
for v_tempo in c_tempo loop
execute immediate
'update CRM.' || v_tempo.tablename || ' set ' || v_tempo.fieldname || ' = null' || ' where customerid = :customerid' using

v_tempo.customerid;
execute immediate
'delete from retentionschedule' || ' where id = :id' || ' and customerid = :customerid' || ' and disposaldate = :

disposaldate' || ' and tablename = :tablename' || ' and fieldname = :fieldname' || ' and disposalaction = :disposalaction'

using v_tempo.id, v_tempo.customerid, v_tempo.disposaldate, v_tempo.tablename, v_tempo.fieldname, v_tempo.disposalaction;
end loop;
commit;

for v_tables in c_tables loop
cursor c_columnname is
'Select COLUMN_NAME from USER_TAB_COLUMNS where TABLE_NAME = ' || v_tables.tablename || ' and column_NAME != (Select

column_name from user_cons_columns where CONSTRAINT_NAME = (
Select constraint_name from user_constraints where constraint_type ='P' and table_name =' || v_tables.tablename ||' ))' using

v_tables.tablename;

count number
statement char
begin
count=0
for v_columnname in c_columnname loop
if count=0
statement = 'delete from v_tables.tablename where' || v_columnname.next || 'is null'
count=1
else
statement = statement || ' and ' || v_columnname.next|| 'is null';

end loop;
commit;
end scheduledelete;
/
Re: How do I loop within a select statement anspass in parameters? [message #6879 is a reply to message #6875] Fri, 09 May 2003 12:19 Go to previous messageGo to next message
Todd Barry
Messages: 4819
Registered: August 2001
Senior Member
First off, you do not need to use dynamic SQL for that delete in the first cursor loop. There is nothing dynamic about it - just use static SQL and the variable values. If you are deleting the row you just processed, that would probably be better done in one statement outside the loop, but I'll leave that alone for now.

As far as evaluating the non-PK columns for a null value, I would make it much simpler by just testing columns that could have NULL values. This will eliminate the PK by definition and any other columns that are NOT NULL. No point in testing those.

I also wouldn't commit partway through the proc. Either everything happens successfully or nothing happens.

So, it might look something like:

create or replace procedure scheduledelete
is 
  cursor c_tempo is 
    select * 
      from retentionschedule 
     where disposalaction = 'Delete' 
       and disposaldate < sysdate;
 
  cursor c_tables is
    select distinct tablename 
      from retentionschedule 
     where disposalaction = 'Delete' 
       and disposaldate < sysdate;
 
  v_sql  varchar2(4000);
begin 
  for v_tempo in c_tempo loop
 
    execute immediate 
      'update CRM.' || v_tempo.tablename || 
      ' set ' || v_tempo.fieldname || ' = null' ||
      ' where customerid = :customerid' using v_tempo.customerid;
 
    delete 
      from retentionschedule
     where id = v_tempo.id
       and customerid = v_tempo.customerid
       and disposaldate = v_tempo.disposaldate
       and tablename = v_tempo.tablename
       and fieldname = v_tempo.fieldname
       and disposalaction = v_tempo.disposalaction; 
 
  end loop;
 
  for v_tables in c_tables loop
 
    v_sql := null;
     
    for c in (select column_name
                from user_tab_columns
               where table_name = v_tables.tablename
                 and nullable = 'Y') loop
 
      v_sql := v_sql || ' and ' || c.column_name || ' is null';
      
    end loop;
    
    if v_sql is not null then
 
      execute immediate
        'delete from ' || v_tables.tablename ||
        ' where ' || ltrim(v_sql, ' and ');
        
    end if;
    
  end loop;      
 
  commit;
 
end scheduledelete;
/
Re: How do I loop within a select statement anspass in parameters? [message #6885 is a reply to message #6879] Fri, 09 May 2003 21:19 Go to previous messageGo to next message
Jennifer
Messages: 20
Registered: September 1999
Junior Member
Hi Todd, thanks for replying the code u have provided my is workgin but I have left out a "CRM." in the select statement "select column_name from user_tab_columns where .......and nullable = 'Y'". The procedure should be:

create or replace procedure scheduledelete is
cursor c_tempo is
select * from retentionschedule where disposalaction = 'Delete' and disposaldate <= sysdate;
cursor c_tables is
select distinct tablename
from retentionschedule where disposalaction = 'Delete' and disposaldate <= sysdate;
v_sql varchar2(4000);
begin
for v_tempo in c_tempo loop
execute immediate
'update CRM.' || v_tempo.tablename || ' set ' || v_tempo.fieldname || ' = null' || ' where customerid = :customerid' using v_tempo.customerid;

delete from retentionschedule where id = v_tempo.id and customerid = v_tempo.customerid and disposaldate = v_tempo.disposaldate and tablename = v_tempo.tablename and fieldname = v_tempo.fieldname and disposalaction = v_tempo.disposalaction;
end loop;
for v_tables in c_tables loop
v_sql := null;
for c in (select column_name from CRM.user_tab_columns where table_name = v_tables.tablename and nullable = 'Y') loop
v_sql := v_sql || ' and ' || c.column_name || ' is null';
end loop;
insert into temp values (v_sql);
if v_sql is not null then
execute immediate
'delete from CRM.' || v_tables.tablename || ' where ' || ltrim(v_sql, ' and ');
end if;
end loop;
commit;
end scheduledelete;
/

The problem now is ,is there anyway a person with "user" role execute the same data as in "select column_name from CRM.user_tab_columns where table_name = v_tables.tablename and nullable = 'Y'" ? because I cannot access it just using "CRM." as "user_tab_columns" belongs to the datadict (not sure about this)
Sorry for the trouble...
Re: How do I loop within a select statement anspass in parameters? [message #6886 is a reply to message #6879] Fri, 09 May 2003 21:50 Go to previous messageGo to next message
Jennifer
Messages: 20
Registered: September 1999
Junior Member
Hi! I have also tried to replace the select statement to "select column_name from DBA_tab_columns where owner = 'CRM' and table_name = v_tables.tablename and nullable = 'Y'" and have also grant the user a DBA role but I have encountered the followign error:
20/10 PL/SQL: SQL Statement ignored
20/34 PL/SQL: ORA-00942: table or view does not exist
21/1 PL/SQL: Statement ignored
21/30 PLS-00364: loop index variable 'C' use is invalid

I have tried executing this select statement by replacing the variable "v_tables.tablename " with a value and was able to execute successfully. What is wrong?
Re: How do I loop within a select statement anspass in parameters? [message #6903 is a reply to message #6885] Sat, 10 May 2003 19:09 Go to previous messageGo to next message
Todd Barry
Messages: 4819
Registered: August 2001
Senior Member
If you are examining tables in another schema, you can use the all_tab_columns view instead of user_tab_columns:

for c in (select column_name from <b>all</b>_tab_columns where <b>owner = 'CRM'</b> and ...
Re: How do I loop within a select statement anspass in parameters? [message #6904 is a reply to message #6886] Sat, 10 May 2003 19:13 Go to previous messageGo to next message
Todd Barry
Messages: 4819
Registered: August 2001
Senior Member
See my other message about using all_tab_columns (there is no need to use dba_tab_columns in this instance). CRM will need to grant the appropriate privileges to the owner of the procedure so the CRM tables in question are visible to the owner via all_tab_columns.
Re: How do I loop within a select statement anspass in parameters? [message #6905 is a reply to message #6903] Sat, 10 May 2003 20:27 Go to previous messageGo to next message
Jennifer
Messages: 20
Registered: September 1999
Junior Member
Hi! I was so relieved that I could get a reply even on weekends! Phew!!
I have already changed it to all_tab_columns but the last delete is not carried out. I suspect that it could be the single quote for v_tables.tablename that I missed out as it is a string. How do I go about adding a ' ' to the Select statement "select column_name from all_tab_columns where table_name = v_tables.tablename and nullable = 'Y' and owner = 'CRM'" as 'CRM' already has got single quote?

Thanks
Re: How do I loop within a select statement anspass in parameters? [message #6918 is a reply to message #6905] Sun, 11 May 2003 18:02 Go to previous message
Todd Barry
Messages: 4819
Registered: August 2001
Senior Member
Well, this isn't dynamic SQL so you don't need to worry about the single quotes as you would if it was part of another string.

You just need to modify the cursor loop as I showed in my last message - query on all_tab_columns instead of user_tab_columns and add the owner = 'CRM' part to the WHERE clause.

You may need to throw a DBMS_OUTPUT line in that loop so you can see the actual DELETE statement that is dynamically built and executed. That should narrow down why something isn't happening the way you think it should be happening...
Previous Topic: check date is later than current date.
Next Topic: TEMP table
Goto Forum:
  


Current Time: Fri Apr 26 04:54:32 CDT 2024