I’m currently learning PL/SQL. I need to create a PL/SQL block to create a backup of all my tables like this : myTable -> myTable_old.
Here’s what I got right now :
DECLARE Cursor c IS SELECT table_name FROM user_tables WHERE table_name NOT LIKE '%_old'; sql_slc VARCHAR2(200); sql_drp VARCHAR2(200); sql_crt VARCHAR2(200); row_count NUMBER; t_name user_tables.table_name%type; t_backup_name user_tables.table_name%type; BEGIN sql_drp := 'DROP TABLE :1 CASCADE'; sql_crt := 'CREATE TABLE :1 AS SELECT * FROM :2'; sql_slc := 'SELECT COUNT(*) FROM user_tables WHERE table_name = :1'; OPEN c; LOOP FETCH c INTO t_name; EXIT WHEN (c%NOTFOUND); t_backup_name := t_name || '_old'; dbms_output.put_line(t_name || ' ' || t_backup_name); EXECUTE IMMEDIATE sql_slc INTO row_count USING t_backup_name; IF row_count > 0 THEN dbms_output.put_line(t_backup_name || ' dropped'); EXECUTE IMMEDIATE sql_drp USING t_backup_name; END IF; dbms_output.put_line(t_backup_name || ' created'); EXECUTE IMMEDIATE sql_crt USING t_backup_name, t_name; COMMIT; END LOOP; CLOSE c; END; /
Here’s the error :
OUVRAGE OUVRAGE_old OUVRAGE_old created DECLARE * ERROR on line 1 : ORA-00903: table name not valid ORA-06512: on line 29
I don’t understand why this error is coming up, can someone help me ?
Advertisement
Answer
The issue is that you can not use bind variables for table names; Oracle documentation:
The database uses the values of bind variables exclusively and does not interpret their contents in any way.
You should edit your code to use concatenation instead:
DECLARE Cursor c IS SELECT table_name FROM user_tables WHERE table_name NOT LIKE '%_OLD'; /* OLD, upper case */ sql_slc VARCHAR2(200); --sql_drp VARCHAR2(200); --sql_crt VARCHAR2(200); row_count NUMBER; t_name user_tables.table_name%type; t_backup_name user_tables.table_name%type; BEGIN -- sql_drp := 'DROP TABLE :1 CASCADE'; -- sql_crt := 'CREATE TABLE :1 AS SELECT * FROM :2'; sql_slc := 'SELECT COUNT(*) FROM user_tables WHERE table_name = :1'; OPEN c; LOOP FETCH c INTO t_name; EXIT WHEN (c%NOTFOUND); t_backup_name := t_name || '_OLD'; /* OLD, upper case */ DBMS_OUTPUT.put_line (t_name || ' ' || t_backup_name); EXECUTE IMMEDIATE sql_slc INTO row_count USING t_backup_name; IF row_count > 0 THEN DBMS_OUTPUT.put_line (t_backup_name || ' dropped'); -- EXECUTE IMMEDIATE sql_drp USING t_backup_name; EXECUTE IMMEDIATE ' drop table ' || t_backup_name; /* concatenation and not bind variables */ END IF; DBMS_OUTPUT.put_line (t_backup_name || ' created'); /* concatenation and not bind variables */ -- EXECUTE IMMEDIATE sql_crt USING t_backup_name, t_name; EXECUTE IMMEDIATE 'create table ' || t_backup_name || ' as select * from ' || t_name; COMMIT; END LOOP; CLOSE c; END;
Also, notice that, if not double quoted, object names always are uppercase, so you have to look for t_name || '_OLD'
and not t_name || '_old'