Here is a hack for your problem. You will have to work on the procedure if you will use it more than once. In particular I do not handle errors, and I look only for VARCHAR2 columns.
SETUP:
create table tbl ( id number, name varchar2(10), notes varchar2(30) );
insert into tbl values ( 1, 'Joe ', 'No notes' );
insert into tbl values ( 2, 'Ann' , 'Spaces ' );
insert into tbl values ( 3, 'Ben' , null );
commit;
select id, '*|'||name||'|*' as name, '*|'||notes||'|*' as notes
from tbl
;
ID NAME NOTES
-- -------------- ----------------------------------
1 *|Joe |* *|No notes|*
2 *|Ann|* *|Spaces |*
3 *|Ben|* *||*
Notice the name in the first row, and the notes in the second - they have trailing spaces. I added leading *| and trailing |* to show where the trailing spaces are.
The proper way to update this table is
update tbl
set name = rtrim(name), notes = rtrim(notes)
where name like '% ' or notes like '% '
;
- notice the WHERE clause, to make sure we don't update rows that don't have any values with trailing spaces. (Updating rows to themselves may seem harmless, but it adds significant overhead, with all the undo and redo they generate.)
So, then, here is PL/SQL code that generates this UPDATE statement dynamically:
create or replace procedure trim_trailing_spaces (
tbl_name in varchar2,
own in varchar2 default null
)
as
sql_text varchar2(4000)
:= 'update ' || nvl(own, user) || '.' || tbl_name;
set_text varchar2(1000)
:= chr(10) || ' set ';
where_text varchar2(1000)
:= chr(10) || ' where ';
begin
for r in ( select column_name as col
from all_tab_columns
where owner = nvl(upper(own), user)
and table_name = upper(tbl_name)
and data_type = 'VARCHAR2'
)
loop
set_text := set_text || r.col || ' = rtrim( ' || r.col || '), ';
where_text := where_text || r.col || ' like ''% '' or ';
end loop;
sql_text := sql_text || rtrim(set_text, ', ') || rtrim(where_text, 'or ');
execute immediate sql_text;
commit;
end trim_trailing_spaces;
/
Compile it and then execute it. I pass in the table name 'tbl' (the table we created earlier) and I don't give the optional second argument (for a schema name different from my own), so the updated table will be the one in my schema. Then I execute the SELECT statement from above to see the changes.
exec trim_trailing_spaces('tbl')
select id, '*|'||name||'|*' as name, '*|'||notes||'|*' as notes
from tbl
;
ID NAME NOTES
-- -------------- ----------------------------------
1 *|Joe|* *|No notes|*
2 *|Ann|* *|Spaces|*
3 *|Ben|* *||*
So, it seems like it worked.