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

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;

Related

Like operator with % in oracle plsql cursor

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;

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;

PLSQL does not compile when substracting two long variables

I'm writing a pretty basic procedure where I need to substract two long variables and assign the value to the other variable. But the code doesn't compile and I am getting hopeless - why is that?
create or replace PROCEDURE TrendCalculator(p_id Prodeje.product%TYPE)
AS
v_week_last Prodeje.WEEK%TYPE;
v_week_current Prodeje.WEEK%TYPE;
v_year_last Prodeje.YEAR%TYPE;
v_year_current Prodeje.YEAR%TYPE;
v_weekly_sales_last PRODEJE.SALES%TYPE;
v_weekly_sales_current PRODEJE.SALES%TYPE;
v_pomocna PRODEJE.SALES%TYPE;
CURSOR c_data IS SELECT WEEK, YEAR, SALES FROM Prodeje WHERE PRODUCT = p_id ORDER BY YEAR, WEEK ASC;
BEGIN
v_pomocna := 0;
OPEN c_data;
LOOP
FETCH c_data INTO v_week_current, v_year_current, v_weekly_sales_current;
EXIT WHEN c_data%NOTFOUND;
IF (v_weekly_sales_last IS NOT NULL) THEN
DBMS_OUTPUT.PUT_LINE(p_id || ' ' || v_week_current || ' ' || v_year_current || ' ' || v_weekly_sales_current);
v_pomocna := (v_weekly_sales_current - v_weekly_sales_last);
END IF;
v_week_last := v_week_current;
v_year_last := v_year_current;
v_weekly_sales_last := v_weekly_sales_current;
END LOOP;
CLOSE c_data;
END;
The Error messages I'm getting are:
Error(19,9): PL/SQL: Statement ignored
Error(19,95): PLS-00306: wrong number or types of arguments in call to '-'
And PRODEJE.SALES Datatype is LONG.
v_weekly_sales_last is not set to anything. So line 19 evaluates to
v_pomocna := (v_weekly_sales_current - );
Which seems to be the cause of your error.

pl sql query takes more time to execute

I found this PL/SQL at my workplace and I couldn't find the reason why this script takes so much time to execute:
DECLARE
query VARCHAR(500);
ref_cur REFCURSOR;
product_listH VARCHAR(1000):='';
product_listA VARCHAR(1000):='';
product_listP VARCHAR(1000):='';
product VARCHAR(100):='';
begin
query := ' select hotelname
from sch1.resconfirmsv rr,
sch1.reshoteldetailssv hd,sch2.respkgconfirmsv r '||
' where rr.id = hd.resconfirmid and
hd.resconfirmid = r.hotelconfirmid and
r.id = ' || m_resconfirmid || '';
OPEN ref_cur FOR EXECUTE query;
LOOP
FETCH ref_cur INTO product;
IF NOT FOUND THEN
EXIT; -- exit loop
END IF;
product_listH := product_listH||''||trim(COALESCE(product,'-'))||',<br>';
END LOOP;
product_listH := rtrim(trim(product_listH),',<br>');
CLOSE ref_cur;
query := ' select distinct programname
from sch1.resconfirmsv rr,
sch3.resactivitysv a,
sch3.resprogramsv hx,
sch2.respkgconfirmsv r '||
' where rr.id = hx.resconfirmid and
hx.id=a.resprogramid and
hx.resconfirmid = r.activitiesconfirmid and
r.id = ' || m_resconfirmid || '';
OPEN ref_cur FOR EXECUTE query;
LOOP
FETCH ref_cur INTO product;
IF NOT FOUND THEN
EXIT; -- exit loop
END IF;
product_listA := product_listA||''||trim(COALESCE(product,'-'))||',<br>';
END LOOP;
product_listA := rtrim(trim(product_listA),',<br>');
CLOSE ref_cur;
product_listP := product_listH || ',<br>' || product_listA;
product_listP := rtrim(trim(product_listP),',<br>');
product_listP = ltrim(rtrim(product_listP,',<br>'),',<br>');
RETURN product_listP;
end;
without this script total run-time is 12.176 sec and with this script it takes up to 18.802 sec.means this gets at least 6 seconds to execute. All the needed columns are indexed. Anybody can tell me where the places need to be more optimize in this query?
Why declaring the cursor as a seperate varchar?
Instead i'd use the normal declaration of a cursor, it takes time to analyze the query to be executed by Oracle, so (between the declare- and Begin-labels of your current code:
cursor ref_cur as
select distinct programname
from sch1.resconfirmsv rr,
sch3.resactivitysv a,
sch3.resprogramsv hx,
sch2.respkgconfirmsv r '||
where rr.id = hx.resconfirmid and
hx.id=a.resprogramid and
hx.resconfirmid = r.activitiesconfirmid and
r.id = m_resconfirmid;
Now you can use
For x in ref_cur loop
The same thing for query#2.
Cheers

Oracle SQL: Find {tags} in a sql string

I have SQL strings that my users write. They look like:
SELECT Name, Age from Users WHERE Name LIKE '%a%' AND {UsersWhere}
On the oracle server side when such an SQL is to be executed I want to replace the {tags} first. The replacements for the {tags} will be valid SQL sub strings I am holding in a table. Pre-manufactered sub sqls. So the treated string will be valid SQL.
Is there some fancy build-in Oracle function to make this happen?
Thanks for a hint!
I have written a small function for anyone interested:
CREATE OR REPLACE FUNCTION SA.REPLACE_VARIABLES (p_sql IN VARCHAR2)
RETURN VARCHAR2
IS
vs_return VARCHAR2 (4000);
-- Deklarationen
vs_sql VARCHAR2(4000);
vs_substring VARCHAR2(4000);
vs_variable VARCHAR2(200);
vs_variable_content VARCHAR2(4000);
BEGIN
vs_sql := p_sql;
IF INSTR(p_sql, '{') > 0 THEN
vs_substring := vs_sql;
WHILE LENGTH(vs_substring) > 0 LOOP
IF INSTR(vs_substring, '{') <> 0
THEN
vs_variable := SUBSTR(vs_substring, INSTR(vs_substring, '{'), INSTR(vs_substring, '}') - INSTR(vs_substring, '{') + 1);
-- Do whatever you want with the variable
--vs_sql := REPLACE(vs_sql, vs_variable, vs_variable_content);
-- Substring verkürzen
vs_substring := SUBSTR(vs_substring, INSTR(vs_substring, vs_variable) + LENGTH(vs_variable) + 1);
ELSE
vs_substring := '';
END IF;
END LOOP;
END IF;
RETURN vs_sql;
EXCEPTION
WHEN OTHERS
THEN
-- Err -handle
END REPLACE_VARIABLES;
/
I'd just keep it simple:
v_sql := REPLACE(v_sql, '{UsersWhere}', '...whatever you need...');