Like operator with % in oracle plsql cursor - sql

I cannot pass the like operator with % in the cursor sql stmt, getting code error, Can you help
SQL> l
1 CREATE OR REPLACE PROCEDURE cleanuptab (
2 isrc_tns VARCHAR2
3 )
4 IS
5 sql_stmt VARCHAR2(500);
6 errm VARCHAR2(2000);
7 refcur SYS_REFCURSOR;
8 v_tabs VARCHAR2(50);
9 BEGIN
10 OPEN refcur FOR 'SELECT table_name FROM dba_tables where table_name like '%''||isrc_tns||''%' and owner='DBASCHEMA'';
11 LOOP
12 BEGIN
13 FETCH refcur INTO v_tabs;
14 EXIT WHEN refcur%NOTFOUND;
15 EXECUTE IMMEDIATE 'drop table DBASCHEMA.'
16 ||v_tabs
17 || ' purge';
18 dbms_output.Put_line('DROPPED '
19 ||v_tabs);
20 EXCEPTION
21 WHEN OTHERS THEN
22 dbms_output.Put_line( 'TABLE NOT FOUND: '
23 ||v_tabs);
24 CONTINUE;
25 END;
26 END LOOP;
27 close refcur;
28* END;
SQL> /
Warning: Procedure created with compilation errors.
SQL> show error
Errors for PROCEDURE CLEANUPTAB:
LINE/COL ERROR
-------- -----------------------------------------------------------------
10/79 PLS-00103: Encountered the symbol "%" when expecting one of the
following:
* & = - + ; < / > at in is mod remainder not rem
<an exponent (**)> <> or != or ~= >= <= <> and or like like2
like4 likec between using || multiset member submultiset
The symbol "* was inserted before "%" to continue.
10/96 PLS-00103: Encountered the symbol "%" when expecting one of the
following:
* & = - + ; < / > at in is mod remainder not rem
<an exponent (**)> <> or != or ~= >= <= <> and or like like2
LINE/COL ERROR
-------- -----------------------------------------------------------------
like4 likec between using || member submultiset
I am trying to pass the like stmt & owner condition so that i can get those tables & drop. Pls help to review
Regards
Kannan

Why not try it without OPEN/FETCH/NOTFOUND, without all the local variables, without the danger of SQL injection, with less lines of codes:
CREATE OR REPLACE PROCEDURE cleanuptab (
isrc_tns VARCHAR2
)
IS
BEGIN
FOR v_tabs IN (SELECT table_name FROM dba_tables WHERE table_name LIKE '%' || isrc_tns || '%' AND owner = 'DBASCHEMA')
LOOP
BEGIN
EXECUTE IMMEDIATE 'drop table DBASCHEMA.' || v_tabs.table_name || ' purge';
dbms_output.put_line('DROPPED ' || v_tabs.table_name );
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('FAILED TO DROP ' || v_tabs.table_name);
END;
END LOOP;
END;

Related

PLS-00103: Encountered the symbol "=" when expecting one of the following.... in PL/SQL script

create or replace function lstnation (listdisplay in varchar2)
return varchar2 is
nName varchar2 (1000) default null;
listD varchar2(1000) default null;
cursor display_nation
is
select nation.n_name
from nation
inner join region
on region.r_regionkey = nation.n_nationkey
where region.r_regionname = listdisplay;
BEGIN
open display_nation;
loop
fetch display_nation into nName;
exit when display_nation%notfound;
IF
listD := listD || RTRIM(nName)||' , ';
end loop;
close display_nation;
return listD;
end lstnation;
/
DECLARE
rKey region.r_regionkey%type;
rName region.r_name%type;
nList varchar2(1000);
cursor outer_block is
select region.r_regionkey, region.r_name, lstnation(region.r_name)
from region;
BEGIN
open outer_block;
loop
fetch outer_block into rKey, rName, nList;
exit when outer_block%notfound;
dbms.output.put_line(rkey || ' ' || RTRIM(rName) || ': '|| nList);
end loop;
close outer_block;
end;
/
I get two errors, how can I fix it
LINE/COL ERROR
19/12 PLS-00103: Encountered the symbol "=" when expecting one of the
following:
. ( * # % & = - + < / > at in is mod remainder not rem then
<an exponent (**)> <> or != or ~= >= <= <> and or like like2
like4 likec between || multiset member submultiset
20/2 PLS-00103: Encountered the symbol "END" when expecting one of the
following:
begin function pragma procedure subtype type
current cursor delete
exists prior
You can save some coding and efficiency by replacing the cursor loop with the listagg function
select listagg(rtrim(nation.n_name),',')
from nation
inner join region
on region.r_regionkey = nation.n_nationkey
where region.r_regionname = listdisplay;
So that will collate all the matching rows, and use whatever delimiter is passed in. One thing to be aware of, you have listD varchar2(1000) so as long as the results from the query are less than 1000, you are OK. If you expect a larger result set, you may need to increase or use a clob.
If for some reason, you still want to use the loop method, then you need to fix your IF statement:
loop
fetch display_nation into nName;
exit when display_nation%notfound;
IF <condition> THEN
listD := listD || RTRIM(nName)||' , ';
END IF;
end loop;

PL/SQL: Cursor doubles the last record from the table

I created the following PL/SQL anonymous block. The cursor below retrieves data from the select statement:
select mod_benutzer, count(*)
from dok_auspraegung
where parent_objekt_id = 1093
group by mod_benutzer;
This statement displays exactly two records:
DDMS_USER | 8
HU2MAMU | 14
But when I want to display these two records by cursor, it displays "HU2MAMU|14" two times like below:
Modifications:
DDMS_USER, 8x
HU2MAMU, 14x
HU2MAMU, 14x
declare
my_exception_1 exception;
var_parent_objekt_id dok_auspraegung.parent_objekt_id%TYPE := 1093;
var_date varchar(30);
var_mod_benutzer varchar2(10);
var_benutzer_modifs number;
cursor cursor_dok_auspraegung
is select mod_benutzer, count(*) from dok_auspraegung
where parent_objekt_id = 10935797565
group by mod_benutzer;
begin
select distinct to_char(mod_datum,'YYYY-MON-DD') into var_date from dok_auspraegung where parent_objekt_id = var_parent_objekt_id;
IF var_date is not null THEN
dbms_output.put_line('Parent Object ID' || ': ' || var_parent_objekt_id);
dbms_output.put_line('Date: ' || ' ' || var_date);
ELSE RAISE my_exception_1;
END IF;
open cursor_dok_auspraegung;
dbms_output.put_line('Modifications:');
loop
fetch cursor_dok_auspraegung into var_mod_benutzer, var_benutzer_modifs;
dbms_output.put(var_mod_benutzer);
dbms_output.put_line(', ' || var_benutzer_modifs || 'x');
exit when cursor_dok_auspraegung%notfound;
end loop;
dbms_output.put_line(cursor_dok_auspraegung%rowcount);
close cursor_dok_auspraegung;
exception
when NO_DATA_FOUND then
dbms_output.put_line('Parent Object ID not found!');
when my_exception_1 then
dbms_output.put_line('');
end;
What is the reason of that?
Because exiting from the cursor occurs after printing the value of the variables in the current case, this repeats the last value to be printed. So, it should occur before printing as follows
loop
fetch cursor_dok_auspraegung into var_mod_benutzer, var_benutzer_modifs;
exit when cursor_dok_auspraegung%notfound;
dbms_output.put(var_mod_benutzer);
dbms_output.put_line(', ' || var_benutzer_modifs || 'x');
end loop;

Prime Number using GOTO statement in PL/SQL

This is my code for Prime Number using goto statement
set serveroutput on;
SQL>
SQL> declare
2 msg varchar2 (30);
3 n pls_integer := 83;
4
5 begin
6 for i in 2..round( sqrt(n) ) loop
7 if n mod i=0 then
8 msg := ' is not a prime number';
9 goto when_prime;
10 end if;
11 end loop;
12
13 msg := ' is a prime number';
14
15 <>
16 dbms_output.put_line(to_char(n) || msg);
17 end;
18 /
I'm getting the following error :
<>
*
ERROR at line 15:
ORA-06550: line 15, column 1:
PLS-00103: Encountered the symbol ">" when expecting one of the following:
( begin case declare end exception exit for goto if loop mod
null pragma raise return select update while with
<an identifier> <a double-quoted delimited-identifier>
<a bind variable> << continue close current delete fetch lock
insert open rollback savepoint set sql execute commit forall
merge pipe purge
ORA-06550: line 16, column 40:
PLS-00103: Encountered the symbol ";" when expecting one of the following:
. ( ) , * % & - + / at mod remainder rem <an exponent (**)>
and or || multiset
I want to check prime number or not a prime number using goto statement
You are not properly declaring the when_prime label.
Just replace this:
<>
With:
<<when_prime>>
Demo on DB Fiddle:
dbms_output:
83 is a prime number
You misused the label declaration section, it should be wrapped in << >> and not < >
Your code should be something like this:
SQL> DECLARE
2 MSG VARCHAR2(30);
3 N PLS_INTEGER := 83;
4 BEGIN
5 FOR I IN 2..ROUND(SQRT(N)) LOOP
6 IF N MOD I = 0 THEN
7 MSG := ' is not a prime number';
8 GOTO WHEN_PRIME;
9 END IF;
10 END LOOP;
11
12 MSG := ' is a prime number';
13 << WHEN_PRIME >>
14 DBMS_OUTPUT.PUT_LINE(TO_CHAR(N) || MSG);
15 END;
16 /
83 is a prime number
PL/SQL procedure successfully completed.
SQL>
UPDATE - Important
May be irrelevant for the error you are getting but you can directly use the following query to find the prime number:
SQL> WITH NUMBR AS (SELECT 83 NUMBR FROM DUAL)
2 SELECT NUMBR,
3 CASE WHEN SUM(CASE WHEN MOD(NUMBR, LEVEL) = 0
4 THEN 1 END) = 1
5 THEN 'prime'
6 ELSE 'not prime'
7 END AS "Prime?"
8 FROM NUMBR
9 CONNECT BY LEVEL <= FLOOR(NUMBR / 2)
10 GROUP BY NUMBR;
NUMBR Prime?
---------- ---------
83 prime
SQL>
Cheers!!

BFILE error on oracle

I would like to make sure that every BFILE in my database really exists on the file system it is related to.
I have the following error :
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: invalid
LOB locator specified: ORA-22275 ORA-06512: at line 59
with the following PL/SQL :
1 declare
2 sSQL varchar2(32767);
3 TYPE refcursor is REF CURSOR;
4 outCursor refcursor;
5 v_1 bfile;
6 dir_alias varchar2(500);
7 name varchar2(500);
8 bfile_exists BOOLEAN := FALSE;
9 --
10 -- DECLARATION DES CURSEURS
11 --
12 cursor find_bfile is
13 SELECT owner, table_name, column_name from dba_tab_columns where data_type='BFILE' order by 1,2,3;
14 begin
15 -- curseur principal sur dba_tab_columns
16 for boucle_find_bfile in find_bfile loop
17 dbms_output.put_line('Owner : ' || boucle_find_bfile.owner || 'Table : ' || boucle_find_bfile.table_name|| boucle_find_bfile.column_name );
18 sSQL := 'select ' || boucle_find_bfile.column_name || ' from ' || boucle_find_bfile.owner || '.' || boucle_find_bfile.table_name;
19 dbms_output.put_line('sSQL : ' || sSQL);
20 OPEN outCursor FOR sSQL;
21 LOOP
22 -- lecture initiale
23 FETCH outCursor INTO v_1;
24 dbms_output.put_line('Avant bfile_exists');
25 begin
26 bfile_exists := DBMS_LOB.FILEEXISTS( v_1 ) = 1;
27 EXCEPTION
28 WHEN DBMS_LOB.NOEXIST_DIRECTORY THEN
29 dbms_output.put_line('>>>>> Directory does not exist !');
30 WHEN DBMS_LOB.NOPRIV_DIRECTORY THEN
31 dbms_output.put_line('>>>>> Directory with privs pb !');
32 WHEN DBMS_LOB.INVALID_DIRECTORY THEN
33 dbms_output.put_line('>>>>> Invalid Directory !');
34 WHEN OTHERS THEN
35 dbms_output.put_line('Milieu : Erreur inattendue : ' || SQLERRM);
36 RAISE;
37 end;
38 dbms_output.put_line('Apres bfile_exists');
39 IF bfile_exists
40 THEN
41 dbms_lob.filegetname(v_1, dir_alias, name);
42 dbms_output.put_line('Table : ' || boucle_find_bfile.table_name || ' / dir_alias : ' || dir_alias || ' / name : ' || name );
43 END IF;
44 EXIT WHEN outCursor%NOTFOUND;
45 -- lecture suivante
46 EXIT WHEN outCursor%NOTFOUND;
47 END LOOP;
48 CLOSE outCursor;
49 end loop; -- fin curseur find_bfile
50 EXCEPTION
51 WHEN DBMS_LOB.NOEXIST_DIRECTORY THEN
52 dbms_output.put_line('>>>>> Directory does not exist !');
53 WHEN DBMS_LOB.NOPRIV_DIRECTORY THEN
54 dbms_output.put_line('>>>>> Directory with privs pb !');
55 WHEN DBMS_LOB.INVALID_DIRECTORY THEN
56 dbms_output.put_line('>>>>> Invalid Directory !');
57 WHEN OTHERS THEN
58 dbms_output.put_line('Fin ; Erreur inattendue : ' || SQLERRM);
59 RAISE;
60* end;
A hint : I have many "bfilename(NULL)" in my LOB type column.
I know I do not use the DBMS_LOB.FILEEXISTS function correctly.
How can I do ?
Thanks in advance
Jean-michel A., Nemours, FRANCE
RDBMS : Oracle 11G on Linux with ASM
First you must fix command
EXIT WHEN outCursor%NOTFOUND;
because it should be located right below
FETCH outCursor INTO v_1;
to finish loop correctly and avoid one invalid iteration:
...
OPEN outCursor FOR sSQL;
LOOP
-- lecture initiale
FETCH outCursor INTO v_1;
EXIT WHEN outCursor%NOTFOUND; -- RIGHT HERE
dbms_output.put_line('Avant bfile_exists');
begin
bfile_exists := DBMS_LOB.FILEEXISTS(v_1) = 1;
EXCEPTION
WHEN DBMS_LOB.NOEXIST_DIRECTORY THEN
dbms_output.put_line('>>>>> Directory does not exist !');
WHEN DBMS_LOB.NOPRIV_DIRECTORY THEN
dbms_output.put_line('>>>>> Directory with privs pb !');
WHEN DBMS_LOB.INVALID_DIRECTORY THEN
dbms_output.put_line('>>>>> Invalid Directory !');
WHEN OTHERS THEN
dbms_output.put_line('Milieu : Erreur inattendue : ' || SQLERRM);
RAISE;
end;
dbms_output.put_line('Apres bfile_exists');
IF bfile_exists THEN
dbms_lob.filegetname(v_1, dir_alias, name);
dbms_output.put_line('Table : ' || boucle_find_bfile.table_name ||
' / dir_alias : ' || dir_alias || ' / name : ' || name);
END IF;
-- EXIT WHEN outCursor%NOTFOUND; not here :/
-- lecture suivante
-- EXIT WHEN outCursor%NOTFOUND; here neither :/
END LOOP;
CLOSE outCursor;
...
About invalid LOB locator: When BFILE columns value are null then DBMS_LOB.FILEEXISTS will throw exception ORA-22275: invalid LOB locator specified. A way to solve the problem is catching this into an exception/when block by ora-code. You can init/declare an exception via pragma as below and catch it later:
declare
invalid_lob_loc exception; -- naming my custom exc as 'invalid_lob_loc'
pragma exception_init(invalid_lob_loc, -22275); -- ORA: 22275
begin
...
begin
...
-- this moment exception will be thrown if BFILE column value is null
bfile_exists = DBMS_LOB.FILEEXISTS(v_1) = 1;
...
exception
when invalid_lob_loc then -- catching it
-- set that file does not exists
bfile_exists = false;
end;
...
end;
Althought, if BFILE column is not null but file does not exists anymore in filesystem then DBMS_LOB.FILEEXISTS will return false and everything will flow as planned :)

Oracle : how to fetch data from dynamic query?

I have a program to generate dynamic query string based on input. This query may select from any tables or joined tables in my DB, and the column names and number of columns are unknown.
Now with this query string as the only input, I want to fetch all data from the result and output them line by line, is there any way to do this ?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Thank Thinkjet for the reference. I have solved the problem, to help the others, here is the piece of code I used:
DECLARE
v_curid NUMBER;
v_desctab DBMS_SQL.DESC_TAB;
v_colcnt NUMBER;
v_name_var VARCHAR2(10000);
v_num_var NUMBER;
v_date_var DATE;
v_row_num NUMBER;
p_sql_stmt VARCHAR2(1000);
BEGIN
v_curid := DBMS_SQL.OPEN_CURSOR;
p_sql_stmt :='SELECT * FROM emp';
DBMS_SQL.PARSE(v_curid, p_sql_stmt, DBMS_SQL.NATIVE);
DBMS_SQL.DESCRIBE_COLUMNS(v_curid, v_colcnt, v_desctab);
-- Define columns:
FOR i IN 1 .. v_colcnt LOOP
IF v_desctab(i).col_type = 2 THEN
DBMS_SQL.DEFINE_COLUMN(v_curid, i, v_num_var);
ELSIF v_desctab(i).col_type = 12 THEN
DBMS_SQL.DEFINE_COLUMN(v_curid, i, v_date_var);
ELSE
DBMS_SQL.DEFINE_COLUMN(v_curid, i, v_name_var, 50);
END IF;
END LOOP;
v_row_num := dbms_sql.execute(v_curid);
-- Fetch rows with DBMS_SQL package:
WHILE DBMS_SQL.FETCH_ROWS(v_curid) > 0 LOOP
FOR i IN 1 .. v_colcnt LOOP
IF (v_desctab(i).col_type = 1) THEN
DBMS_SQL.COLUMN_VALUE(v_curid, i, v_name_var);
ELSIF (v_desctab(i).col_type = 2) THEN
DBMS_SQL.COLUMN_VALUE(v_curid, i, v_num_var);
ELSIF (v_desctab(i).col_type = 12) THEN
DBMS_SQL.COLUMN_VALUE(v_curid, i, v_date_var);
END IF;
END LOOP;
END LOOP;
DBMS_SQL.CLOSE_CURSOR(v_curid);
END;
/
You can do that with DBMS_SQL package.
Update
To get more detailed reference about DBMS_SQL go here.
If you are building your string within PL/SQL, you can run it with EXECUTE IMMEDIATE. <- link. Use the BULK COLLECT INTO and output the collection.
<PRE>
DECLARE
RUN_S CLOB;
IGNORE NUMBER;
SOURCE_CURSOR NUMBER;
PWFIELD_COUNT NUMBER DEFAULT 0;
L_DESCTBL DBMS_SQL.DESC_TAB2;
Z_NUMBER NUMBER;
BEGIN
RUN_S := ' SELECT 1 AS VAL1,
2 AS VAL2,
CURSOR (SELECT 11 AS VAL11,
12 AS VAL12
FROM DUAL) AS CUR1,
CURSOR (SELECT 11 AS VAL11,
12 AS VAL12
FROM DUAL) AS CUR2
FROM DUAL';
SOURCE_CURSOR := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(SOURCE_CURSOR, RUN_S, DBMS_SQL.NATIVE);
DBMS_SQL.DESCRIBE_COLUMNS2(SOURCE_CURSOR, PWFIELD_COUNT, L_DESCTBL); -- get record structure
FOR I IN 1 .. PWFIELD_COUNT LOOP
DBMS_OUTPUT.PUT_LINE('Col ' || I || ' Type:' || L_DESCTBL(I).COL_TYPE);
IF L_DESCTBL(I).COL_TYPE = 2 THEN
DBMS_SQL.DEFINE_COLUMN(SOURCE_CURSOR, I, Z_NUMBER);
END IF;
NULL;
END LOOP;
IGNORE := DBMS_SQL.EXECUTE(SOURCE_CURSOR);
LOOP
IF DBMS_SQL.FETCH_ROWS(SOURCE_CURSOR) > 0 THEN
FOR I IN 1 .. PWFIELD_COUNT LOOP
IF L_DESCTBL(I).COL_TYPE IN (2) THEN
DBMS_SQL.COLUMN_VALUE(SOURCE_CURSOR, I, Z_NUMBER);
DBMS_OUTPUT.PUT_LINE('Col ' || I || ' Value:' || Z_NUMBER);
END IF;
END LOOP;
ELSE
EXIT;
END IF;
END LOOP;
END;
</PRE>