Simple PL/SQL to check if table exists is not working - sql

I'm in the process of converting some stored procedures from Sybase TSQL to Oracle PL/SQL and I've already come across a problem which I'm struggling to resolve!
The below code will not run:
DECLARE
t INT := 0;
t_error EXCEPTION;
v_line VARCHAR2(100);
BEGIN
SELECT COUNT(*) INTO t FROM user_tables WHERE table_name = UPPER('tbl_BSUK_PriceIssue');
IF t = 1 THEN
EXECUTE IMMEDIATE 'DROP TABLE tbl_BSUK_PriceIssue';
t := 0;
SELECT COUNT(*) INTO t FROM user_tables WHERE table_name = UPPER('tbl_BSUK_PriceIssue');
IF t = 1 THEN
RAISE t_error;
END IF;
END IF;
EXCEPTION
WHEN t_error THEN
v_line := '<<< FAILED DROPPING table tbl_BSUK_PriceIssue >>>';
dbms_output.put_line (v_line);
WHEN OTHERS THEN
v_line := '<<< Unknown Error >>>';
dbms_output.put_line (v_line);
END;
END;
I get the following error message, what am I doing wrong?!
Error starting at line : 17 in command - DECLARE
t INT := 0; t_error EXCEPTION; v_line VARCHAR2(100);
BEGIN
SELECT COUNT(*) INTO t FROM user_tables WHERE table_name =
UPPER('tbl_BSUK_PriceIssue');
IF t = 1 THEN EXECUTE IMMEDIATE 'DROP TABLE tbl_BSUK_PriceIssue';
t := 0; SELECT COUNT(*) INTO t FROM user_tables WHERE table_name =
UPPER('tbl_BSUK_PriceIssue'); IF t = 1 THEN
RAISE t_error; END IF; END IF;
EXCEPTION WHEN t_error THEN v_line := '<<< FAILED DROPPING table
tbl_BSUK_PriceIssue >>>'; dbms_output.put_line (v_line); WHEN
OTHERS THEN
v_line := '<<< Unknown Error >>>';
dbms_output.put_line (v_line); END;
END; Error report - ORA-06550: line 30, column 1: PLS-00103: Encountered the symbol "END"
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
I'm actually trying to replace the following TSQL with a PL/SQL version:
-- Create temp table for relevant trev_id's
IF OBJECT_ID('dbo.tbl_BSUK_PriceIssue') IS NOT NULL
BEGIN
DROP TABLE dbo.tbl_BSUK_PriceIssue
IF OBJECT_ID('dbo.tbl_BSUK_PriceIssue') IS NOT NULL
PRINT '<<< FAILED DROPPING TABLE dbo.tbl_BSUK_PriceIssue >>>'
ELSE
PRINT '<<< DROPPED TABLE dbo.tbl_BSUK_PriceIssue >>>'
END
go

try to remove END; in this section
WHEN OTHERS THEN
v_line := '<<< Unknown Error >>>';
dbms_output.put_line (v_line);
END;
UPD. Actually, you can do it a bit shorter, no need to check if table exists after drop
declare
eTableNotExists exception;
pragma exception_init(eTableNotExists, -00942);
begin
EXECUTE IMMEDIATE 'DROP TABLE tbl_BSUK_PriceIssue';
dbms_output.put_line('<<< DROPPED TABLE dbo.tbl_BSUK_PriceIssue >>>');
exception
when eTableNotExists then null
when others then
dbms_output.put_line ('<<< Unknown Error >>>' || sqlerrm);
end;
/

I don't know about the error, but you can do what you want in a fraction of the code. You don't need the count variable if you use EXISTS() and you don't need EXECUTE IMMEDIATE because you don't have variable data in the command:
IF 1 = (SELECT 1 FROM user_tables WHERE table_name = 'TBL_BSUK_PRICEISSUE') THEN
DROP TABLE tbl_BSUK_PriceIssue;
IF 1 = (SELECT 1 FROM user_tables WHERE table_name = 'TBL_BSUK_PRICEISSUE') THEN
RAISE EXCEPTION;
END IF;
END IF;

Related

How to drop and create table again and again

when i use this code first time ,it create the table but i want to use this code again and again but second time when i use it ,it will drop the table but does not create table again . kindly help me to correct the code according to my requirement.
set serverout on
DECLARE
table_or_view_does_not_exist exception;
pragma exception_init(table_or_view_does_not_exist,-00942);
ddl_qry VARCHAR2 (200);
ddl_table varchar2(200);
r_emp SYS.ODCINUMBERLIST := SYS.ODCINUMBERLIST();
v_array SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST('ACCT_ID',
'PARENT_ACCT_ID',
'CUST_ID',
'ACCT_NAME',
'BILLING_CYCLE_TYPE',
'PAID_FLAG',
'BILL_DELIVER_METHOD');
BEGIN
ddl_qry:='Drop Table Accnt_Profile_Spcl';
EXECUTE IMMEDIATE ddl_qry;
exception
when table_or_view_does_not_exist then
dbms_output.put_line('There is no error');
GOTO end_point;
<<end_point>>
ddl_table := 'create table Accnt_Profile_Spcl(
column_name varchar2(50),
spcl_char_count number)';
EXECUTE IMMEDIATE ddl_table;
dbms_output.put_line('Table has been created');
---------DBMS_OUTPUT.ENABLE;
FOR i IN 1..v_array.COUNT LOOP
r_emp.EXTEND;
EXECUTE IMMEDIATE
'SELECT /*+parallel(16)*/ COUNT(*) FROM account_profile WHERE NOT REGEXP_LIKE('||v_array(i)||',''[A-Za-z0-9.]'')'
INTO r_emp(i);
if r_emp(i)<>0 then
-----------dbms_output.put_line(v_array(i) || ': ' || r_emp(i));
execute immediate 'insert into Accnt_Profile_Spcl values (:param1,:param2)' using v_array(i), r_emp(i);
end if;
END LOOP;
END;
That's bad practice. You should really avoid dropping and creating tables that way, that's not how Oracle is supposed to work. Create table once, at SQL level, and reuse it as many times as you want. Just remove its contents, if you want / have to.
Anyway: here's how you could do that:
SQL> declare
2 l_cnt number;
3 begin
4 select count(*) into l_cnt
5 from user_tables
6 where table_name = 'ACCNT_PROFILE_SPCL';
7
8 if l_cnt = 1 then
9 execute immediate 'drop table ACCNT_PROFILE_SPCL';
10
11 dbms_output.put_line('Table dropped');
12 end if;
13
14 execute immediate 'create table ACCNT_PROFILE_SPCL ' ||
15 ' (column_name varchar2(50),' ||
16 ' spcl_char_count number)';
17
18 dbms_output.put_line('Table created');
19 end;
20 /
Table dropped
Table created
PL/SQL procedure successfully completed.
SQL> /
Table dropped
Table created
PL/SQL procedure successfully completed.
SQL>
Use a nested block to handle the exception and not the main block:
DECLARE
ddl_qry VARCHAR2 (200);
ddl_table varchar2(200);
r_emp SYS.ODCINUMBERLIST := SYS.ODCINUMBERLIST();
v_array SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST('ACCT_ID',
'PARENT_ACCT_ID',
'CUST_ID',
'ACCT_NAME',
'BILLING_CYCLE_TYPE',
'PAID_FLAG',
'BILL_DELIVER_METHOD');
BEGIN
DECLARE
table_or_view_does_not_exist EXCEPTION;
PRAGMA EXCEPTION_INIT(table_or_view_does_not_exist,-00942);
BEGIN
ddl_qry:='Drop Table Accnt_Profile_Spcl';
EXECUTE IMMEDIATE ddl_qry;
EXCEPTION
WHEN table_or_view_does_not_exist THEN
dbms_output.put_line('There is no error');
END;
ddl_table := 'create table Accnt_Profile_Spcl(
column_name varchar2(50),
spcl_char_count number)';
EXECUTE IMMEDIATE ddl_table;
dbms_output.put_line('Table has been created');
FOR i IN 1..v_array.COUNT LOOP
r_emp.EXTEND;
EXECUTE IMMEDIATE
'SELECT /*+parallel(16)*/ COUNT(*) FROM account_profile WHERE NOT REGEXP_LIKE('||v_array(i)||',''[A-Za-z0-9.]'')'
INTO r_emp(i);
if r_emp(i)<>0 then
execute immediate 'insert into Accnt_Profile_Spcl values (:param1,:param2)' using v_array(i), r_emp(i);
end if;
END LOOP;
END;
/
fiddle

Statements in if statement with false condition are executed

I have created this guard function:
create or replace
FUNCTION checkTableExists (tableName varchar2)
RETURN BOOLEAN
IS c INT;
BEGIN
SELECT COUNT(*) INTO c FROM user_tables where table_name = upper(tableName);
return c = 1;
END;
I try to use it like:
IF checkTableExists ('NO_TABLE') THEN
DELETE FROM NO_TABLE;
END IF;
Even though the table doesn't exist, I get:
Error report:
ORA-06550: line 6, column 17:
PL/SQL: ORA-00942: table or view does not exist
ORA-06550: line 6, column 5:
PL/SQL: SQL Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
How do I get around this? Dynamic SQL?
UPDATE: I get no error if I run:
IF checkTableExists ('NO_TABLE') THEN
dbms_output.put_line('argh');
END IF;
And argh is not output. If I run the above with a table that does exist, argh is output as expected.
Your statement is parsed completly. So if you replace
DELETE FROM NO_TABLE;
by
null;
your statement should work.
Your error message was a little bit misleading because in line 6 is the select on user_tables and the delete is in line 2 in a different statement. This makes it harder to debug.
So you have to use dynamic sql:
execute immidiate 'delete from ' || 'NO_TABLE';
Don't use a guard function; just try to delete the table and catch the exception if it does not exist:
DECLARE
table_not_exists EXCEPTION;
PRAGMA EXCEPTION_INIT( table_not_exists, -942 );
BEGIN
EXECUTE IMMEDIATE 'DELETE FROM no_table';
DBMS_OUTPUT.PUT_LINE( 'deleted' );
EXCEPTION
WHEN table_not_exists THEN
DBMS_OUTPUT.PUT_LINE( 'did not exist' );
END;
/
db<>fiddle
If you don't want to initialise the exception in lots of different PL/SQL blocks then initialise once it in a package:
CREATE PACKAGE exceptions IS
table_not_exists EXCEPTION;
PRAGMA EXCEPTION_INIT( table_not_exists, -942 );
END;
/
and the code is then simply:
BEGIN
EXECUTE IMMEDIATE 'DELETE FROM no_table';
DBMS_OUTPUT.PUT_LINE( 'deleted' );
EXCEPTION
WHEN EXCEPTIONS.table_not_exists THEN
DBMS_OUTPUT.PUT_LINE( 'did not exist' );
END;
/
db<>fiddle
If you do want to use your guard function (I'd advise that you don't) then just use EXECUTE IMMEDIATE:
IF checkTableExists ('NO_TABLE') THEN
EXECUTE IMMEDIATE 'DELETE FROM NO_TABLE';
END IF;

Unable to pass schema name in execute immediate

I am trying to pass as a parameter the schema name into an execute immediate command.
DECLARE
sql_stmt VARCHAR2(200);
BEGIN
sql_stmt := 'DROP INDEX :owner.".MY_INDEX"';
EXECUTE IMMEDIATE sql_stmt using &owner_name ;
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN
RAISE;
END IF;
END;
The above raises following oracle error:
ORA-06550: line 5, column 38:
PLS-00201: identifier 'USER_X' must be declared
I have tried also tried to concatenate the sql_stmt without success though. I receive the exact same error as above:
DECLARE
sql_stmt VARCHAR2(200);
BEGIN
sql_stmt := 'DROP INDEX ' || &owner. || '".MY_INDEX";';
EXECUTE IMMEDIATE sql_stmt ;
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN
RAISE;
END IF;
END;
Any suggestions to pass the username as a variable in the execute statement?
I found that the following works. I was missing a dot '.':
DECLARE
sql_stmt VARCHAR2(200);
BEGIN
sql_stmt := 'DROP INDEX &owner_name.."MY_INDEX"';
EXECUTE IMMEDIATE sql_stmt;
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN
RAISE;
END IF;
END;
A better approach would be assigning values through variables not directly to the execute immediate. If you use variables then this block can be reused for other purposes too. Always try to make blocks in such a way it can be reused. Hope below snippet helps.
SET define ON;
DECLARE
sql_stmt VARCHAR2(200);
lv_chema_nm VARCHAR2(100):='&Enter_schema_name';
lv_obj_type VARCHAR2(100):='&Enter_obj_type';
lv_obj_name VARCHAR2(100):='&Enter_obj_name';
BEGIN
sql_stmt := 'DROP '||lv_obj_type ||' '|| lv_chema_nm||'.'||lv_obj_name;
EXECUTE IMMEDIATE sql_stmt ;
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN
RAISE;
END IF;
END;

how handle table or view does not exist exception?

I have a set of table names, let say 150. Each table have mail_id column, now I want to search one mail_id in all of the table. For that I wrote one Plsql block. When I loop through the set of table some tables do not exists so it raises an exception. I have exception handling block to handle that exception. Now I want to loop entire table even though it raise an exception? Any idea? Actually my block didn't handle that particular exception!
declare
my_mail_id varchar2(50):='xyaksj#jsm.com';
tmp_table varchar2(125);
type varchar_collector is table of varchar2(255);
var varchar_collector;
table_does_not_exist exception;
PRAGMA EXCEPTION_INIT(table_does_not_exist, -00942);
begin
for cntr in (select table_name from user_tables)
loop
tmp_table:=cntr.table_name;
dbms_output.put_line(tmp_table);
for mail in (select email_address from tmp_table where lower(email_address) like '%my_mail_id%' )
loop
dbms_output.put_line(tmp_table);
end loop;
end loop;
exception
when no_data_found then
dbms_output.put_line('email address not found');
WHEN table_does_not_exist then
dbms_output.put_line('table dose not exists');
WHEN OTHERS THEN
--raise_application_error(-20101, 'Expecting at least 1000 tables');
IF (SQLCODE = -942) THEN
--DBMS_Output.Put_Line (SQLERRM);
DBMS_Output.Put_Line ('in exception');--this exception not handled
ELSE
RAISE;
END IF;
end;
Just handle your exceptions in anonymous block inside the loop.
DECLARE
my_mail_id VARCHAR2(50) := 'xyaksj#jsm.com';
tmp_table VARCHAR2(125);
TYPE varchar_collector IS TABLE OF VARCHAR2(255);
var varchar_collector;
table_does_not_exist EXCEPTION;
PRAGMA EXCEPTION_INIT(table_does_not_exist, -00942);
BEGIN
FOR cntr IN (SELECT table_name FROM user_tables)
LOOP
BEGIN
tmp_table := cntr.table_name;
dbms_output.put_line(tmp_table);
FOR mail IN (SELECT email_address
FROM tmp_table
WHERE lower(email_address) LIKE '%my_mail_id%')
LOOP
dbms_output.put_line(tmp_table);
END LOOP;
EXCEPTION
WHEN no_data_found THEN
dbms_output.put_line('email address not found');
WHEN table_does_not_exist THEN
dbms_output.put_line('table dose not exists');
WHEN OTHERS THEN
--raise_application_error(-20101, 'Expecting at least 1000 tables');
IF (SQLCODE = -942)
THEN
--DBMS_Output.Put_Line (SQLERRM);
DBMS_Output.Put_Line('in exception'); --this exception not handled
ELSE
RAISE;
END IF;
END;
END LOOP;
END;
If you're selecting from user_tables and finding that some of them do not exist then you're probably trying to query tables that are in the recycle bin (their names begin BIN$).
If so, change your query to:
select table_name
from user_tables
where dropped = 'NO';
You should replace your second cursor with a call to execute immediate also, constructing the query by concatenating in the table_name not just using a variable as the table name, and you might as well construct the query as:
select count(*)
from table_name
where lower(email_address) like '%my_mail_id%'
and rownum = 1;
That way you'll retrieve a single record that is either 0 or 1 to indicate whether the email address was found, and no need for error handling.
try below code...
DECLARE
foo BOOLEAN;
BEGIN
FOR i IN 1..10 LOOP
IF foo THEN
GOTO end_loop;
END IF;
<<end_loop>> -- not allowed unless an executable statement follows
NULL; -- add NULL statement to avoid error
END LOOP; -- raises an error without the previous NULL
END;

cursor giving error

hi we are trying to execute following script we
are getting errors as
ERROR at line 1:
ORA-20000: Unknown Exception Raised: -933 ORA-00933: SQL command not properly
ended
ORA-06512: at line 23
DECLARE
l_cursor INTEGER;
l_output VARCHAR2(20);
l_rows INTEGER;
l_sql VARCHAR2(1000);
BEGIN
l_cursor := DBMS_SQL.OPEN_CURSOR;
l_sql := 'SELECT wk_units1 FROM cnt_sls_dm.fct_sales.summary UNION SELECT wk_units2 FROM cnt_sls_dm.fct_sales.summary';
DBMS_SQL.PARSE(l_cursor, l_sql, DBMS_SQL.NATIVE);
DBMS_SQL.DEFINE_COLUMN_CHAR(l_cursor, 1, l_output, 20);
l_rows := DBMS_SQL.EXECUTE(l_cursor);
loop
if DBMS_SQL.FETCH_ROWS(l_cursor) = 0 then
exit;
end if;
DBMS_SQL.COLUMN_VALUE_CHAR(l_cursor, 1, l_output);
DBMS_OUTPUT.PUT_LINE('Output Text '||l_output);
end loop;
DBMS_SQL.CLOSE_CURSOR(l_cursor);
EXCEPTION
when others then
DBMS_SQL.CLOSE_CURSOR(l_cursor);
raise_application_error(-20000, 'Unknown Exception Raised: '||sqlcode||' '||sqlerrm);
END;
What is this?
cnt_sls_dm.fct_sales.summary
It's not a valid table declaration.
When encountering an error in a dynamic SQL statement, it often helps to output the actual SQL statement and try it in SQLplus.