Why this PL/SQL doesn't work? - plsql

Im trying to learn PL/SQL. I am struck with this code. Please notify me where im going wrong. I use Oracle 10g in a command line .
declare
grade char(1):='&v_grade';
app varchar(15);
begin
app:=case v_grade
when 'a' then
dbms_output.put_line('Excellent');
when 'b' then
dbms_output.put_line('Good');
else
dbms_output.put_line('Bad');
end case;
dbms_output.put_line('Grade'||grade||' Appraisal:'||app);
end;
/
It shows
Enter value for v_grade: a
old 2: grade char(1):='&v_grade';
new 2: grade char(1):='a';
dbms_output.put_line('Excellent');
*
ERROR at line 7:
ORA-06550: line 7, column 34:
PLS-00103: Encountered the symbol ";" when expecting one of the following:
. ( * % & = - + < / > at else end in is mod remainder not rem
when <an exponent (**)> <> or != or ~= >= <= <> and or like
LIKE2_ LIKE4_ LIKEC_ between || multiset member SUBMULTISET_
The symbol ";" was ignored.
ORA-06550: line 9, column 29:
PLS-00103: Encountered the symbol ";" when expecting one of the following:
. ( * % & = - + < / > at else end in is mod remainder not rem
when <an exponent (**)> <> or != or ~= >= <= <> and or like
LIKE2_ LIKE4_ LIKEC_ between ||
ORA-06550: line 11, column 28:
PLS-00103: Encountered the symbol ";" when expecting one of the following:
. ( * % & = - + < / > at end in is mod remainder not rem
<an exponent (**)> <> or != or ~= >= <= <> and or like LIKE2_
LIKE4_ LIKEC_ between || multiset
please notify me where i am going wrong.

T.J. Crowder is sort of right, you shouldn't have a semicolon within a case statement in SQL, but this is the PL/SQL version so it's slightly different.
You are currently trying to assign the (non-existent) return from the dbms_output.put_line procedure (not function) call to your app variable.
For the assignment to work you need the case to evaluate to a string, so you can just use text literals; but the assignment needs to be in each branch:
declare
grade char(1):='&v_grade';
app varchar(15);
begin
case grade
when 'a' then app:= 'Excellent';
when 'b' then app:= 'Good';
else app := 'Bad';
end case;
dbms_output.put_line('Grade '||grade||' Appraisal: '||app);
end;
/
Which when run gets:
Enter value for v_grade: a
Grade b Appraisal: Excellent
PL/SQL procedure successfully completed.
Or use a query to do the assignment, though this is not quite as efficient:
declare
grade char(1):='&v_grade';
app varchar(15);
begin
select case grade
when 'a' then 'Excellent'
when 'b' then 'Good'
else 'Bad'
end case
into app
from dual;
dbms_output.put_line('Grade '||grade||' Appraisal: '||app);
end;
/
Enter value for v_grade: b
Grade b Appraisal: Good
PL/SQL procedure successfully completed.
Or you can do the output directly in each branch:
declare
grade char(1):='&v_grade';
begin
dbms_output.put('Grade '||grade||' Appraisal: ');
case grade
when 'a' then
dbms_output.put_line('Excellent');
when 'b' then
dbms_output.put_line('Good');
else
dbms_output.put_line('Bad');
end case;
end;
/
Enter value for v_grade: c
Grade c Appraisal: Bad
PL/SQL procedure successfully completed.
The first part of your output is before the case now.
You're basically mixing up the different approaches.
You might want to change the first line to:
grade char(1):= upper('&v_grade');
... and then make the case look for A,B,C instead of a,b,c - then it won't matter what case the input is in.
You can read more about the PL/SQL case statemnt here and here.

Related

Simple if else statement is not working in MariaDB

Update:
I want to insert data conditionally
Why this MariaDB query has errors:
if 2 > 1 then
select 'hi'
else
select 'bye'
end if
This is the error:
Error in query (1064): Syntax error near 'else select 'bye' end if' at line 3
if (exists (select * from teachers where name = 'Jennifer'))
then
-- do nothing
else
insert into teachers (name, age)
values ('Jennifer', 30)
end if;
I'm not sure that IF can be used like this outside of a stored procedure or function. You may use the IF() function or a CASE expression instead:
SELECT IF(2 > 1, 'hi', 'bye')
OR
SELECT CASE WHEN 2 > 1 THEN 'hi' ELSE 'bye' END

PL/SQL Calling a function to a procedure

Previously,I asked about creating a function that returns total amount of salaries from a parameter city.
I chose Dallas for instance.Tables are EMP and DEPT:
You can find them below
https://livesql.oracle.com/apex/livesql/file/content_O5AEB2HE08PYEPTGCFLZU9YCV.html
Mistakenly I wrote in my language instead of english at the end of it but I corrected it.
Now I need to create a procedure which lists ascending the employees and their salaries from another parameter city.After listing them I need to call the function for the second city.Problem is I get an error for the 'loop' from the procedure and i got no idea why.
set serveroutput on;
create or replace function show_sal (local dept.loc%type) return number as
vval number;
begin
select sum(emp.sal)
into vval
from emp inner join dept on dept.deptno = emp.deptno
where upper(dept.loc) = upper(local);
return vval;
end;
/
begin
dbms_output.put_line('Total sum of salaries from DALLAS = ' || show_sal('DALLAS'));
end;
/
-------------------------------------------------------------------------------------------------
CREATE OR REPLACE PROCEDURE show_employees(v_loc dept.loc%TYPE) AS
CURSOR c IS
SELECT ename,sal
FROM emp INNER JOIN dept ON emp.deptno = dept.deptno
WHERE UPPER(loc)=UPPER(v_loc)
ORDER BY ename ASC;
v_name VARCHAR2;
v_salaries emp.sal%TYPE;
BEGIN
OPEN c
LOOP
FETCH c INTO v_name,v_salaries;
EXIT WHEN c%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_name||' '|| v_salaries);
END LOOP;
CLOSE c;
END;
/
EXECUTE show_employees('CHICAGO');
BEGIN
show_sal('CHICAGO');
END;
/
You simply forgot the semicolon after OPEN c.
And here is how to do the same with an implicit cursor, which is much easier to deal with in my opinion:
CREATE OR REPLACE PROCEDURE show_employees(v_loc dept.loc%TYPE) AS
BEGIN
FOR rec IN
(
SELECT ename, sal
FROM emp
WHERE deptno IN (SELECT deptno FROM dept WHERE UPPER(loc) = UPPER(v_loc))
ORDER BY ename
) LOOP
DBMS_OUTPUT.PUT_LINE(rec.ename || ' ' || rec.sal);
END LOOP;
END show_employees;
Errors i get:
Function SHOW_SAL compiled
Total sum of salaries from DALLAS = 10875
PL/SQL procedure successfully completed.
Procedure SHOW_EMPLOYEES compiled
LINE/COL ERROR
9/9 PLS-00215: String length constraints must be in range (1 .. 32767)
Errors: check compiler log
Error starting at line : 40 in command -
BEGIN show_employees('CHICAGO'); END;
Error report -
ORA-06550: line 1, column 61:
PLS-00905: object HR.SHOW_EMPLOYEES is invalid
ORA-06550: line 1, column 61:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
Error starting at line : 42 in command -
BEGIN
show_sal('CHICAGO');
END;
Error report -
ORA-06550: line 2, column 1:
PLS-00221: 'SHOW_SAL' is not a procedure or is undefined
ORA-06550: line 2, column 1:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
set serveroutput on;
create or replace function show_sal (local dept.loc%type) return number as
vval number;
begin
select sum(emp.sal)
into vval
from emp inner join dept on dept.deptno = emp.deptno
where upper(dept.loc) = upper(local);
return vval;
end;
/
begin
dbms_output.put_line('Total sum of salaries from DALLAS = ' || show_sal('DALLAS'));
end;
/
-------------------------------------------------------------------------------------------------
CREATE OR REPLACE PROCEDURE show_employees(v_loc dept.loc%TYPE) AS
CURSOR C is SELECT ename,sal
FROM emp,dept
WHERE emp.deptno=dept.deptno AND UPPER(loc)=UPPER(v_loc)
ORDER BY ename ASC;
v_nume emp.ename%TYPE;
v_salariu emp.sal%TYPE;
v_tot emp.sal%TYPE;
BEGIN
v_tot:=show_sal('CHICAGO');
dbms_output.put_line('nume salar total: '||v_tot);
OPEN C;
LOOP
FETCH C INTO v_nume,v_salariu;
EXIT WHEN C%NOTFOUND;
dbms_output.put_line(v_nume||' '||v_salariu);
END LOOP;
CLOSE C;
END;
/
EXECUTE show_employees('CHICAGO');

How to define spool file with substitution variable

I'm using Oracle sql plus to execute a script PL/SQL.
Here’s my script:
set serveroutput on
spool "Svincoli_giornalieri.csv"
declare
v_id_rapporto number(20);
begin
v_id_rapporto := &id_rapporto;
select id_rapporto into v_id_rapporto from tb_ag_rapporti where id_rapporto = v_id_rapporto;
for c in (
select r.intestazione,vn.id_rapporto,vn.IMPORTO_SVINCOLABILE,vn.IMPORTO_ORIG,svn.ID_OP_VNC,svn.importo,svn.DATA_INS,svn.STATO_CSE ,svn.DATA_ESECUZIONE
from tb_op_vnc vn, TB_OP_SVN svn, tb_ag_rapporti r
where vn.ID_OP_VNC=svn.ID_OP_VNC
and r.id_rapporto =vn.id_rapporto
and svn.DATA_INS>trunc(sysdate)
)
loop
dbms_output.put_line( c.intestazione||' idr: '||c.id_rapporto||' ID_Vincolo:'||c.ID_OP_VNC||' '||c.stato_cse||' Data Esec: '||c.DATA_ESECUZIONE||' Importo orig:'||c.IMPORTO_ORIG||' Svincolo Residuo:'||c.IMPORTO_SVINCOLABILE||' Importo Svincolato:'||c.importo);
end loop;
end;
/
spool off
I want to pass the output in a spool file using the substitution variable but when I launch my script I get this error:
ERRORE alla riga 6:
ORA-06550: riga 6, colonna 26:
PLS-00103: Trovato il simbolo "OFF" anziche uno dei seguenti:
. ( * # %
& = - + ; < / > at in is mod remainder not rem
<un esponente (**)> <> o != o ~= >= <= <> and or like like2
like4 likec between || multiset member submultiset
Il simbolo "." e stato sostituito per permettere a "OFF" di continuare.
I can’t figure out how to solve this problem. Could someone help me? Thanks
To dynamically specify a spool file in SQL*Plus you migt want to use something like:
column filename new_val filename
select 'file_' || to_char(sysdate, 'yyyymmdd' ) filename from dual;
spool &filename
Unfortunately I do not understand how this relates to the (Italian) error message you also posted.
If you could show the complete output including the line numbers and an english error text this might be better to understand.
Is the error in the line with "spool off" and did you try to add a blank line before the spool off?

PL/SQL update based on flag

I have a table "flags" containing flags with "name" and "value" where "name" is the name of the flag and "value" is either 'T' or 'F'
I would like to update a table based on a flag with name 'enable_feature' in the following manner:
BEGIN;
IF ((SELECT flags.value FROM flags WHERE flags.name = 'enable_feature') = 'T')
UPDATE... SET...;
ELSE
UPDATE... SET...;
END IF;
END;
My trouble seems to be in the IF statement. Specifically, i get the following error:
PLS-00103: Encountered the symbol "SELECT" when expecting one of the
following:
( - + case mod new not null continue avg count current
exists max min prior sql stddev sum variance execute forall merge
time timestamp interval date pipe
How do I modify this statement such that I can perform an UPDATE/SET statement based on the value of 'enable_feature' (The UPDATE/SET statement is on a different table)
DECLARE
v flags.value%type;
BEGIN
SELECT flags.value into v FROM flags WHERE flags.name = 'enable_feature';
IF v = 'T' THEN
UPDATE... SET...;
ELSE
UPDATE... SET...;
END IF;
END;

PLS-00103 when running script in APEX

I'm trying to run the following PLSQL script in APEX:
DECLARE
total NUMBER;
BEGIN
SELECT COUNT(*)
INTO total
FROM one_table;
FOR i IN 0:100 --This is line 8
LOOP
INSERT INTO other_table(id, column_a) SELECT id + i * total, column_a FROM one_table;
END LOOP;
COMMIT;
END;
And I get this error:
ORA-06550: line 8, column 15: PLS-00103: Encountered the symbol "" when expecting one of the following: * & - + / at mod remainder rem .. <an exponent (**)> || multiset The symbol ".." was substituted for "" to continue.'
I don't think this is legal syntax:
FOR i IN 0:100
I think you mean:
FOR i IN 0..100

Resources