Encountered symbol "DROP" when expecting one of the following - oracle

Hi I am writing a simple set of oracle statements but I am getting an error saying "PLS-00103: Encountered the symbol DROP when expecting one of the following". I am not sure what is wrong with my statements. Any help is appreciated.
DECLARE
table_exists number := 0;
BEGIN
SELECT COUNT(*) INTO table_exists FROM dba_tables WHERE owner = 'ABC'
AND table_name = 'XYZ';
If (table_exists = 1) then
DROP TABLE "ABC"."XYZ";
End If;
End;

If you want use DDL statements in PL/SQL blocks, you have to use dynamic SQL.
Try this:
execute immediate 'DROP TABLE ' || owner.table_name

Related

ORA-00922: missing or invalid option when trying to create column in table

I'm using the following code for create a column in an existing table, but, I'm getting this error:
ORA-00922: missing or invalid option
I've tried get the desired result (create column in table "only if this column does not exists") without the EXECUTE IMMEDIATE instruction, but, PL/SQL doesn't allow use the ALTER TABLE [...] in an IF [] THEN structure.
Is there something I'm missing?
This is the db<>fiddle sample:
CREATE TABLE "TMP_TABLE_SAMPLE"
( "ID_TABLE" NUMBER(9,0)
) ;
✓
SET SERVEROUTPUT ON;
CLEAR SCREEN;
DECLARE
V_COLUMN_EXISTS NUMBER := 0;
BEGIN
SELECT COUNT(1) CONTEO
INTO V_COLUMN_EXISTS
FROM USER_TAB_COLS
WHERE UPPER(COLUMN_NAME) = 'PNT_NCODE'
AND UPPER(TABLE_NAME) = 'TMP_TABLE_SAMPLE';
IF V_COLUMN_EXISTS = 0 THEN
EXECUTE IMMEDIATE 'ALTER TABLE TMP_TABLE_SAMPLE ADD PNT_NCODE NUMBER (9,0) ' ||
' COMMENT ON COLUMN TMP_TABLE_SAMPLE.PNT_NCODE IS ''Stores ID from TMP_TABLE_SAMPLE_2.''';
ELSE
DBMS_OUTPUT.PUT_LINE('Column already exists');
END IF;
END;
ORA-00922: missing or invalid option
The error you're getting is because you have set serveroutput on and clear screen in your script. db<>fiddle knows how to interpret SQL and PL/SQL. It doesn't support SQL*Plus commands.
If you remove those, the next error you'll get is that you have a single execute immediate statement that is trying to execute two separate statements. Creating the column and adding a comment on the column are separate operations so you need separate statements.
If I change your fiddle to this, it works the way you want
DECLARE
V_COLUMN_EXISTS NUMBER := 0;
BEGIN
SELECT COUNT(1) CONTEO
INTO V_COLUMN_EXISTS
FROM USER_TAB_COLS
WHERE UPPER(COLUMN_NAME) = 'PNT_NCODE'
AND UPPER(TABLE_NAME) = 'TMP_TABLE_SAMPLE';
IF V_COLUMN_EXISTS = 0 THEN
EXECUTE IMMEDIATE 'ALTER TABLE TMP_TABLE_SAMPLE ADD PNT_NCODE NUMBER (9,0) ';
EXECUTE IMMEDIATE 'COMMENT ON COLUMN TMP_TABLE_SAMPLE.PNT_NCODE IS ''Stores ID from TMP_TABLE_SAMPLE_2.''';
ELSE
DBMS_OUTPUT.PUT_LINE('Column already exists');
END IF;
END;
/

getting error while compiling the stored procedure

I am writing this below stored procedure but i am also getting the exception while compiling the procedure in oracle, below is the procedure
CREATE OR REPLACE PACKAGE BODY TEST_TABLE AS
PROCEDURE TEST_TABLE
--This procedure will delete partitions for the following tables:
--TEST_TABLE
BEGIN
FOR cc IN
(
SELECT partition_name, high_value
FROM user_tab_partitions
WHERE table_name = 'TEST_TABLE'
)
LOOP
EXECUTE IMMEDIATE 'BEGIN
IF sysdate >= ADD_MONTHS(' || cc.high_value || ', 3) THEN
EXECUTE IMMEDIATE
''ALTER TABLE TEST_TABLE DROP PARTITION ' || cc.partition_name || '
'';
END IF;
dbms_output.put_line('drop partition completed');
END;';
END LOOP;
exception
when others then
dbms_output.put_line(SQLERRM);
END;
END;
/
and the exception that I am getting it while compiling is Please advise how to overcome from this.
Error(7,1): PLS-00103: Encountered the symbol "BEGIN" when expecting one of the following: ( ; is with authid as cluster order using external deterministic parallel_enable pipelined result_cache The symbol ";" was substituted for "BEGIN" to continue.
Error(22,25): PLS-00103: Encountered the symbol "DROP" when expecting one of the following: * & = - + ; < / > at in is mod remainder not rem return returning <an exponent (**)> <> or != or ~= >= <= <> and or like like2 like4 likec between into using || bulk member submultiset
You need to make correct quotation as below( and one more is keyword just after PROCEDURE TEST_TABLE "thanks to Alex who make me awaken" ) :
CREATE OR REPLACE PACKAGE BODY PKG_TEST_TABLE IS
PROCEDURE TEST_TABLE IS
--This procedure will delete partitions for the following tables:
--TEST_TABLE
BEGIN
FOR cc IN
(
SELECT partition_name, high_value
FROM user_tab_partitions
WHERE table_name = 'TEST_TABLE'
)
LOOP
BEGIN
IF sysdate >= ADD_MONTHS(cc.high_value, 3) THEN
EXECUTE IMMEDIATE
'ALTER TABLE TEST_TABLE DROP PARTITION ' || cc.partition_name;
Dbms_Output.Put_Line('Dropping partition is completed.');
END IF;
END;
END LOOP;
EXCEPTION WHEN Others THEN Dbms_Output.Put_Line( SQLERRM );
END TEST_TABLE;
END PKG_TEST_TABLE;
/
As a little suggestion use a different name for package than procedure such as PKG_TEST_TABLE against confusion.
Edit : of course you need to create a specification part for a package before the body part of the package :
CREATE OR REPLACE PACKAGE PKG_TEST_TABLE IS
PROCEDURE TEST_TABLE;
END PKG_TEST_TABLE;
/
The first error message tells you something is missing before BEGIN, and even mentions the two possible options in the 'when expecting' list. You need to change it to:
PROCEDURE TEST_TABLE IS
-- ^^
Or you can use AS instead of IS if you prefer...
The second error is because you have a string literal embedded in your dynamic SQL and you haven't escaped the single quotes, though you have elsewhere:
...
dbms_output.put_line(''drop partition completed'');
-- ^ ^
END;';
You could use the alternative quoting mechanism instead.
I'm not sure why you're doing two levels of dynamic SQL; you can do the dbms_output() and evaluate cc.high_value statically, and decide whether to make the alter call, with only that part dynamic (as #BarbarosÖzhan has shown, so I wont repeat that!). Or do the high-value check within the cursor query.
I am still getting exception Error(1,14): PLS-00304: cannot compile body of 'TEST_TABLE' without its specification
If you want a package then you have to create its specification before you try to create its body:
CREATE OR REPLACE PACKAGE TEST_TABLE AS
PROCEDURE TEST_TABLE;
END TEST_TABLE;
/
CREATE OR REPLACE PACKAGE BODY TEST_TABLE AS
PROCEDURE TEST_TABLE IS
BEGIN
FOR cc IN
...
LOOP
...
END LOOP;
END TEST_TABLE; -- end of procedure
END TEST_TABLE; -- end of package
/
Having the package name the same as a procedure within it is a bit odd and confusing.
But maybe you didn't actually want a package at all, and were trying to create a standalone procedure, in which case just remove the package-body part:
CREATE OR REPLACE PROCEDURE TEST_TABLE AS
BEGIN
FOR cc IN
...
LOOP
...
END LOOP;
END TEST_TABLE; -- end of procedure
/
Read more.
I would strongly suggest you get rid of the exception handler, and I've left that out of those outlines - you should let any exception flow back to the caller. You don't know that whoever calls this will even have output enabled, so might well not even see the message you're printing instead. Only ever catch exceptions you can handle and need to handle at that point.

Store Procedure hit SQL Statement Ignored

create or replace PROCEDURE GEN_STATEMENT_SP(indexNM IN VARCHAR2, tableNM IN VARCHAR2) AS
BEGIN
DECLARE
uniqueSTMT VARCHAR2(30);
nonUniqueSTMT VARCHAR2(30);
charOn VARCHAR2(5);
tempfld VARCHAR2(500) ;
CURSOR chkTyp IS(SELECT ES_UNIQUENESS from sys.dba_ind_columns where INDEX_NAME = indexNM and TABLE_NAME = tableNM);
CURSOR tblColumn IS(SELECT INDEX_NAME,listagg(COLUMN_NAME, ',') WITHIN GROUP (ORDER BY COLUMN_POSITION) COLUMN_NAME FROM sys.dba_ind_columns where INDEX_NAME = indexNM and TABLE_NAME = tableNM GROUP BY INDEX_NAME);
BEGIN
uniqueSTMT := 'CREATE UNIQUE INDEX';
nonUniqueSTMT := 'CREATE INDEX';
charOn := 'on';
if chkTyp.ES_UNIQUENESS = 'UNIQUE' then
tempfield := uniqueSTMT || indexNM || charOn || tableNM || '(' || tblColumn.COLUMN_NAME || ')' ;
DBMS_OUTPUT.put_line(tempfld);
end if;
END;
END;
/
Error list:
LINE/COL ERROR
-------- ------------------------------------------------------------------
9/17 PL/SQL: SQL Statement ignored
9/48 PL/SQL: ORA-00942: table or view does not exist
10/20 PL/SQL: SQL Statement ignored
10/126 PL/SQL: ORA-00942: table or view does not exist
18/1 PL/SQL: Statement ignored
18/11 PLS-00225: subprogram or cursor 'CHKTYP' reference is out of scope
Hi all, when i try to create a sample store procedure above. I hit SQL Statement ignored.
Need some help on this, Thanks alot.
You don't have access to DBA_ views (owned by SYS). Do you really need those? Switch to USER_IND_COLUMNS instead. Once you make that code work, expand it further (if necessary).
As of CHKTYP being improperly used: you declared a cursor, but never did anything with it (opened, fetched, ..., closed). On the other hand, why do you use cursors? Those are SELECT statements that return a single value (unless I'm wrong), so they might have been ordinary SELECTs (but yes, you might have to handle possible NO-DATA-FOUND exception).
Furthermore, there's no column ES_UNIQUENESS in USER_IND_COLUMNS view; what is is supposed to do? It exists in USER_INDEXES, but is called UNIQUENESS, without the ES_ prefix.
Shortly, you need to rewrite that code. Take it step by step, test frequently. Once you're sure that the first step was successful, go to the next.

Invalid table name error, when execute alter stored procedure in oracle

-- Disable constaint, good
CREATE OR REPLACE PROCEDURE cpl_disable_constraint(table_name IN varchar2, constraint_name IN varchar2)
AS
BEGIN
execute immediate 'ALTER TABLE :1 DISABLE CONSTRAINT :2' using table_name, constraint_name;
END;
/
-- Bug
declare
table_name varchar2(100) := 'ADV_TEST_COURSE_CREDIT';
column_name varchar2(100) := 'SEQUENCE_NUMBER';
begin
cpl_disable_constraint(table_name, column_name);
end;
/
I'm getting these errors:
ORA-00903: invalid table name
ORA-06512: at "SISD_OWNER.CPL_DISABLE_CONSTRAINT", line 5
ORA-06512: at line 5
00000 - "invalid table name"
Any idea?
As a_horse_with_no_name mentioned, you can't pass an identifier to execute immediate as a parameter. You have to put it in the SQL statement.
execute immediate 'ALTER TABLE ' || table_name || ' DISABLE CONSTRAINT :1' using constraint_name;
Note that this will open you up to SQL Injection if you don't carefully validate the table_name variable. I usually do something like this before calling execute immediate, to make sure the table_name variable is the valid and correct table name for the constraint, and not some malicious string like null; DROP TABLE ADV_TEST_COURSE_CREDIT;:
select c.table_name into table_name from user_constraints c where c.constraint_name = constraint_name;
(By the way, this is part of why people often choose a prefix for local PL/SQL variable names, like "v_table_name", to keep them separate from column names. You can see it's a little confusing in the query above.)
Also I'd like to point out that in your function definition, you're calling the second parameter "constraint_name", but in the anonymous block you're calling it "column_name".

oracle drop index if exists

How do you drop an index only if it exists?
It seems simple but I did found anything on the net.
The idea is to drop it only if it exists, because if not, I will have an error and my process stops.
I found this to find if the index exists:
select index_name
from user_indexes
where table_name = 'myTable'
and index_name='myIndexName'
But I don't know how to put it together with
DROP INDEX myIndexName
Don't check for existence. Try to drop, and capture the exception if necessary...
DECLARE
index_not_exists EXCEPTION;
PRAGMA EXCEPTION_INIT (index_not_exists, -1418);
BEGIN
EXECUTE IMMEDIATE 'drop index foo';
EXCEPTION
WHEN index_not_exists
THEN
NULL;
END;
/
DECLARE
COUNT_INDEXES INTEGER;
BEGIN
SELECT COUNT ( * )
INTO COUNT_INDEXES
FROM USER_INDEXES
WHERE INDEX_NAME = 'myIndexName';
-- Edited by UltraCommit, October 1st, 2019
-- Accepted answer has a race condition.
-- The index could have been dropped between the line that checks the count
-- and the execute immediate
IF COUNT_INDEXES > 0
THEN
EXECUTE IMMEDIATE 'DROP INDEX myIndexName';
END IF;
END;
/
In Oracle, you can't mix both DDL and DML. In order to do so, you need to work it around with the EXECUTE IMMEDIATE statement.
So, first check for the existence of the index.
Second, drop the index through the EXECUTE IMMEDIATE statement.
DECLARE v_Exists NUMBER;
BEGIN
v_Exists := 0;
SELECT 1 INTO v_Exists
FROM USER_INDEXES
WHERE TABLE_NAME LIKE 'myTable'
AND INDEX_NAME LIKE 'myIndexName'
IF v_Exists = 1 THEN
EXECUTE IMMEDIATE "DROP INDEX myIndexName"
ENDIF;
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
This code is out the top of my head and you may need to fix it up a little, but this gives an idea.
Hope this helps! =)
I made a procedure so it can be called several times:
DELIMITER €€
DROP PROCEDURE IF EXISTS ClearIndex€€
CREATE PROCEDURE ClearIndex(IN var_index VARCHAR(255),IN var_table VARCHAR(255))
BEGIN
SET #temp = concat('DROP INDEX ', var_index, ' ON ', var_table);
PREPARE stm1 FROM #temp;
BEGIN
DECLARE CONTINUE HANDLER FOR 1091 SELECT concat('Index ', var_index,' did not exist in ',var_table,', but was handled') AS 'INFO';
EXECUTE stm1;
END;
END €€
DELIMITER ;
Now it can be called more than once:
CALL ClearIndex('employees_no_index','employees');
CALL ClearIndex('salaries_no_index','salaries');
CALL ClearIndex('titles_no_index','titles');
I hope this will help. It's a combination of all solution :)
By the way thanks for the help !
CREATE OR REPLACE PROCEDURE CLEAR_INDEX(INDEX_NAME IN VARCHAR2) AS
BEGIN
EXECUTE IMMEDIATE 'drop index ' || INDEX_NAME;
EXCEPTION
WHEN OTHERS THEN
NULL;
END CLEAR_INDEX;

Resources