Is this prcedure syntaxically wrong? It seems that there is a problem with my if than block. I kepp getting
PLS-00103: Encountered the symbol ")" when expecting one of the
following:
(
CREATE OR REPLACE PROCEDURE Verif(TAB VARCHAR2) IS
MAX NUMBER;
TEMP NUMBER;
BEGIN
FOR i IN (SELECT * FROM CLIENTS1_1 WHERE NOT REGEXP_LIKE (COL2, (SELECT REGULAREXPR FROM REGULAREXPRES WHERE CATEGORY='ABR'))) LOOP
MAX:=0;
FOR j IN (SELECT * FROM ABR) LOOP
SELECT UTL_MATCH.JARO_WINKLER_SIMILARITY(i.Col2, j.ABR) INTO TEMP FROM DUAL;
IF (TEMP >= MAX) THEN
DBMS_OUTPUT.PUT_LINE(TEMP);
end if;
END LOOP;
END LOOP;
END;
/
I did all the tests. All select queries return real values.
Thanks for your help.
It was a stupid mistake. Just needed to replace MAX (which is a key word) by another var name.
Thanks to Barbaros Ozhan.
Related
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.
I am trying to update the 'damage_amt' of cars by increasing the value by 'inc', but only for accidents that occurred in year 'year'.
CREATE or REPLACE PROCEDURE updateDMG(xyear VARCHAR2, inc NUMBER) AS
CURSOR cur1 IS
select a.DAMAGE_AMT
from participated a join accident b
on a.report_nr = b.report_nr
for update;
p_dmg PARTICPATED.damage_amt%TYPE;
p_year NUMBER;
inc_dmg NUMBER;
BEGIN
p_year:=xyear;
inc_dmg:=inc;
OPEN cur1;
LOOP
FETCH cur1 bulk collect INTO p_dmg;
EXIT WHEN cur1%NOTFOUND;
UPDATE PARTICIPATED
SET damage_amt = damage_amt * inc_dmg
WHERE p_dmg like xyear;
END LOOP;
CLOSE cur1;
END updateDMG;
/
EXEC updateDMG('08', 0.10);
But I'm getting the error:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following: begin function pragma procedure subtype <an identifier> <a double-quoted delimited-identifier> current cursor delete exists prior
Obviously I am lacking knowledge on the syntax of this type of answer. Can anyone point out my error? I can't seem to find anything from searching.
EDIT: Was missing a / after END. Now it doesn't actually update the rows.
FINAL EDIT: Figured it out. I think some of my variables are unnecessary, but I could be wrong.
CREATE or REPLACE PROCEDURE updateDMG(xyear NUMBER, inc DECIMAL) AS
CURSOR cur1 IS
select a.DAMAGE_AMT, extract(year from b.ACCIDENT_DATE)
from participated a join accident b
on a.report_nr = b.report_nr
for update;
p_dmg PARTICIPATED.damage_amt%TYPE;
p_year NUMBER;
input_year NUMBER;
inc_dmg DECIMAL;
BEGIN
input_year:=xyear;
inc_dmg:=inc;
OPEN cur1;
FETCH cur1 INTO p_dmg, p_year;
MERGE INTO PARTICIPATED x
USING ACCIDENT y
ON (x.report_nr = y.report_nr)
WHEN MATCHED THEN
UPDATE SET x.damage_amt = x.damage_amt * (1 + inc_dmg/100)
WHERE extract(year from y.accident_date) = input_year;
CLOSE cur1;
END updateDMG;
/
EXEC updateDMG(2008, 10);
I don't have a database right now to fully check syntax, but I would suggest something like this:
CREATE OR REPLACE PROCEDURE updatedmg (p_year NUMBER, p_inc DECIMAL)
AS
l_next_year NUMBER;
l_from_date DATE;
l_to_date DATE;
BEGIN
l_next_year := p_year + 1;
l_from_date := TO_DATE (p_year || '-01-01', 'RRRR-MM-DD');
l_to_date := TO_DATE (l_next_year || '-01-01', 'RRRR-MM-DD');
UPDATE participated pt
SET pt.damage_amt = pt.damage_amt * (1 + p_inc / 100)
WHERE pd.report_nr IN (SELECT ad.report_nr
FROM accident ad
WHERE ad.accident_date >= l_from_date
AND ad.accident_date < l_to_date);
END updatedmg;
Its simple and that way you probably can make better use of indexes on tables.
I hope it helps.
Good luck!
I am researching issues regarding oracle. I'm creating stored procedures and boot the following errors I also show them in the picture, I hope to help me resolve the error.
[]
You can add variable v_count number :=0; in your procedure to check if value exists.
Example:
CREATE OR REPLACE PROCEDURE PROCEDURE_NAME(PARAMETERS) IS
V_COUNT NUMBER := 0;
BEGIN
SELECT COUNT(1)
INTO V_COUNT
FROM YOUR_TABLE
WHERE .. .
IF V_COUNT = 0 THEN INSERT ...
ELSIF UPDATE ...
COMMIT;
END IF;
END;
Merge is one way to do this. Another way is
INSERT INTO..
SELECT ....
FROM DUAL
WHERE NOT EXISTS (SELECT * FROM...)
I'm not going to try and transcribe your screenshot
I previously asked a question in stackoverflow regarding a certain function that I was having a hard time with and I found the answer when I saw the RETURN statement missing.
Now, I am dealing with a procedure that calls for the input text letters to be converted to UPPER if in the LOWER case and vice versa.
e.g IF I put in 'AbC' it should return 'aBc'
So far this is my code
CREATE OR REPLACE PROCEDURE Opposite_Case (p_string IN VARCHAR2)
IS
var_string VARCHAR2(20);
var_contain VARCHAR2(20);
i NUMBER;
BEGIN
var_string:=substr(Opposite_Case.p_string,i,1);
var_contain:= var_string || var_contain;
FOR i in 1.. length(var_string)
LOOP
BEGIN
IF var_string IN ('ABCDEFGHIJKLMNOPQRSTUVWXYZ') THEN
SELECT LOWER(var_string) INTO var_contain FROM dual;
ELSE
SELECT UPPER(var_string) INTO var_contain FROM dual;
END IF;
END;
END LOOP;
END;
/
BUT the following error is returned:
EXECUTE Opposite_Case('AbC')
begin Opposite_Case('AbC'); end;
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at "SYS.OPPOSITE_CASE", line 10
ORA-06512: at line 1
Thanks in advance.
PS. This is just my 3rd day with a PL/SQL language so please bear with me.
EDIT: I got it to work finally thanks to #Satya's help. Now I get to convert them like it should but how do I output my selects in one line though?
I'm almost there. Appreciate the help a lot from this community!!
What I have so far:
SQL> EXECUTE Opposite_Case('AbC')
A
b
C
PL/SQL procedure successfully completed
You should investigate the TRANSLATE function. To use it to switch the case of the characters in your string you'd do something like the following:
SELECT TRANSLATE('AbC',
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
FROM DUAL;
which should return 'aBc'.
SQLFiddle here
Share and enjoy.
Finally found the answer! Thanks guys! (without TRANSLATE though)!
CREATE OR REPLACE PROCEDURE Opposite_Case (p_string IN VARCHAR2)
IS
var_string VARCHAR2(20);
var_contain VARCHAR2(20);
i NUMBER;
BEGIN
FOR i in 1.. length(p_string)
LOOP
BEGIN
var_string:=substr(p_string,i,1);
var_contain:= var_string;
IF var_string IN ('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z') THEN
SELECT LOWER(var_string) INTO var_contain FROM dual;
DBMS_OUTPUT.PUT(var_contain);
ELSE
SELECT UPPER(var_string) INTO var_contain FROM dual;
DBMS_OUTPUT.PUT(var_contain);
END IF;
END;
END LOOP;
dbms_output.new_line;
END;
/
CREATE OR REPLACE PROCEDURE get_pop1
AS
ROUTERNAME_V varchar2(100);
BEGIN
SELECT TRAFFIC_CUST_ID
INTO ROUTERNAME_V
FROM INTERFACE_ATTLAS
WHERE rownum < 2;
IF CHARINDEX('RNS',ROUTERNAME_V) > 0
dbms_output.put_line(routername_v);
ELSE
PRINT 'It doesn''t Contain'
END;
/* HERE I AM TRYING TO DISPLAY THE RECORDS ONLY IT STARTS WITH 'RNS' STRING
I am getting error like :
10/3 PLS-00103: Encountered the symbol "DBMS_OUTPUT" when expecting
one of the following:
* & - + / at mod remainder rem then and or
|| multiset
The symbol "*" was substituted for "DBMS_OUTPUT" to continue.
10/37 PLS-00103: Encountered the symbol ";" when expecting one of the
following:
. ( * % & - + / at mod remainder rem then
and or || */
CHARINDEX and PRINT are not Oracle functions. Unless you've defined those yourself as wrappers, you'll need to switch to functions Oracle does recognise. You're also missing THEN and END IF.
CREATE OR REPLACE PROCEDURE get_pop1
AS
ROUTERNAME_V varchar2(100);
BEGIN
SELECT TRAFFIC_CUST_ID
INTO ROUTERNAME_V
FROM INTERFACE_ATTLAS
WHERE rownum < 2;
IF INSTR(ROUTERNAME_V, 'RNS') > 0 THEN
dbms_output.put_line(routername_v);
ELSE
dbms_output.put_line('It doesn''t Contain');
END IF;
END;
/
You said you wanted the string to start with RNS, and INSTR will find it anywhere; you'd need to test that it returns exactly 1, not > 0.
You could also do:
IF ROUTERNAME_V LIKE 'RNS%' THEN
DBMS_OUTPUT puts the text into a buffer that something else can then retrieve, so you'll only see anything if your client is expecting this when it is executed (not just when it is compiled); e.g. with set serveroutput on in SQL*Plus, or by opening the DBMS Output panel in SQL Developer. You generally shouldn't rely on that being available.
set serveroutput on
exec get_pop1;
The get in the procedure name suggests that maybe you really want a function that returns the value, or the fixed string if it doesn't match your pattern.
CREATE OR REPLACE FUNCTION get_pop2
RETURN VARCHAR2 AS
ROUTERNAME_V varchar2(100);
BEGIN
SELECT TRAFFIC_CUST_ID
INTO ROUTERNAME_V
FROM INTERFACE_ATTLAS
WHERE rownum < 2;
IF ROUTERNAME_V LIKE 'RNS%' THEN
RETURN(routername_v);
ELSE
RETURN('It doesn''t Contain');
END IF;
END;
/
Then you can do:
select get_pop2 from dual;
It might be worth noting that you're selecting an arbitrary row from your table. If it has more than one row there is nothing to determine which one you get; the same query against the same data could get a different row back. You need a filter and/or an order by to control which you get, e.g. the most recent record if they are time-stamped.
CREATE OR REPLACE PROCEDURE get_pop1
AS
ROUTERNAME_V varchar2(100);
BEGIN
SELECT TRAFFIC_CUST_ID
INTO ROUTERNAME_V
FROM INTERFACE_ATTLAS
WHERE TRAFFIC_CUST_ID LIKE '%RNS%' and rownum < 2;
IF CHARINDEX('RNS',ROUTERNAME_V) > 0 THEN
dbms_output.put_line(routername_v);
END;
I'm not sure you want the String RNS at the beginning or not, you may want to replace '%RNS%' by 'RNS%'.