Oracle Missing keyword in oracle issue - oracle

I tried finetuning the query which is as below.
select (CASE WHEN v_yearMSA <> 0 THEN to_char((1 + V_CALPER_INCR2 / v_yearMSA * 2.5) / 100, '99990D999') END);
it's giving me error as
Error(786,105): PL/SQL: ORA-00905: missing keyword

You're missing the FROM clause.
With dummy sample data:
SQL> SELECT CASE
2 WHEN v_yearmsa <> 0
3 THEN
4 TO_CHAR ((1 + v_calper_incr2 / v_yearmsa * 2.5) / 100,
5 '99990D999')
6 END
7 FROM test;
CASEWHENV_
----------
0.260
SQL>
If it is PL/SQL, then you might not even need SELECT (if v_ represent local variables that got their values elsewhere):
SQL> SET SERVEROUTPUT ON
SQL>
SQL> DECLARE
2 v_yearmsa NUMBER := 1;
3 v_calper_incr2 NUMBER := 10;
4 result VARCHAR2 (20);
5 BEGIN
6 result :=
7 CASE
8 WHEN v_yearmsa <> 0
9 THEN
10 TO_CHAR ((1 + v_calper_incr2 / v_yearmsa * 2.5) / 100,
11 '99990D999')
12 END;
13 DBMS_OUTPUT.put_line (result);
14 END;
15 /
0.260
PL/SQL procedure successfully completed.
SQL>
If you're now missing INTO, it means that you're in PL/SQL and - in there - selects require INTO. Something like this:
declare
result varchar2(20);
begin
SELECT CASE
WHEN v_yearmsa <> 0
THEN
TO_CHAR ((1 + v_calper_incr2 / v_yearmsa * 2.5) / 100,
'99990D999')
END
INTO result --> this
FROM test;
end;
/

Related

How I can creating all the tables, a trigger must be written so that the IDs are entered automatically

Create Table table8_prc (
Family VARCHAR2(200),
Name VARCHAR2(200) ,
ID INTEGER
) ;
CREATE SEQUENCE ID_seq1
MINVALUE 1
START WITH 1
INCREMENT BY 1
CACHE 20;
Create or Replace trigger trg1
BEFORE insert on table8_prc
for each row
BEGIN
select ID_seq1.nextval into :new.ID from dual ;
END ;
CREATE OR REPLACE PROCEDURE addnewmem1 (str IN VARCHAR2)
AS
BEGIN
INSERT INTO table8_prc (Name, Family)
WITH
temp
AS
( SELECT REGEXP_SUBSTR (str,
'[^,]+',
1,
LEVEL) val
FROM DUAL
CONNECT BY LEVEL <= REGEXP_COUNT (str, ',') + 1)
SELECT ID,SUBSTR (val, 1, INSTR (val, ';') - 1),
SUBSTR (val, INSTR (val, ';') + 1)
FROM temp;
COMMIT;
END;
BEGIN
addnewmem1 ('faezeh;Ghanbarian,pari;izadi');
END;
BEGIN
addnewmem1 ('Saeed;Izadi,Saman; Rostami');
END;
You're close. Fix number of columns to be inserted.
Table, sequence and trigger:
SQL> CREATE TABLE table8_prc
2 (
3 Family VARCHAR2 (200),
4 Name VARCHAR2 (200),
5 ID INTEGER
6 );
Table created.
SQL> CREATE SEQUENCE ID_seq1 MINVALUE 1 START WITH 1 INCREMENT BY 1 CACHE 20;
Sequence created.
SQL> CREATE OR REPLACE TRIGGER trg1
2 BEFORE INSERT
3 ON table8_prc
4 FOR EACH ROW
5 BEGIN
6 SELECT ID_seq1.NEXTVAL INTO :new.ID FROM DUAL;
7 END;
8 /
Trigger created.
Procedure:
SQL> CREATE OR REPLACE PROCEDURE addnewmem1 (str IN VARCHAR2)
2 AS
3 BEGIN
4 INSERT INTO table8_prc (Name, Family)
5 WITH
6 temp
7 AS
8 ( SELECT REGEXP_SUBSTR (str,
9 '[^,]+',
10 1,
11 LEVEL) val
12 FROM DUAL
13 CONNECT BY LEVEL <= REGEXP_COUNT (str, ',') + 1)
14 SELECT TRIM (SUBSTR (val, 1, INSTR (val, ';') - 1)),
15 TRIM (SUBSTR (val, INSTR (val, ';') + 1))
16 FROM temp;
17
18 COMMIT;
19 END;
20 /
Procedure created.
Testing:
SQL> BEGIN
2 addnewmem1 ('faezeh;Ghanbarian,pari;izadi');
3 addnewmem1 ('Saeed;Izadi,Saman; Rostami');
4 END;
5 /
PL/SQL procedure successfully completed.
SQL> SELECT * FROM table8_prc;
FAMILY NAME ID
-------------------- -------------------- ----------
Ghanbarian faezeh 1
izadi pari 2
Izadi Saeed 3
Rostami Saman 4
SQL>

How to reverse a number using PLSQL

I am trying to write a PLSQL code to revers the number
SET SERVEROUTPUT ON;
DECLARE
v_num number :=120;
v_store_values NUMBER;
v_length NUMBER;
v_output NUMBER;
BEGIN
SELECT LENGTH(v_num) INTO v_length FROM DUAL;
FOR v_counter IN 1..v_length LOOP
SELECT SUBSTR(v_num,-(v_counter),v_counter) INTO v_store_values FROM DUAL;
DBMS_OUTPUT.PUT_LINE(v_store_values);
END LOOP;
END;
/
It gives me the output :
0
2
1
But I want the output on horizontal : 021
You don't really need PL/SQL; consider
SQL> select listagg(substr('120', -level, 1)) result
2 from dual
3 connect by level <= length('120');
RESULT
--------------------------------------------------------------------------------
021
SQL>
If it has to be PL/SQL:
SQL> declare
2 result varchar2(20);
3 begin
4 select listagg(substr('120', -level, 1)) result
5 into result
6 from dual
7 connect by level <= length('120');
8
9 dbms_output.put_line(result);
10 end;
11 /
021
PL/SQL procedure successfully completed.
SQL>
You can use the simple REVERSE function below but Please note it is an undocumented feature.
select reverse(to_char(120))
from dual;
OR you can use the supported utl_raw.reverse
select utl_raw.cast_to_varchar2(utl_raw.reverse(utl_raw.cast_to_raw (to_char(120))))
from dual;

Procedure error - PLS-00103 Encountered the symbol ">"

I am trying to learn PLSQL and I have a problem creating a procedure.
The task I am solving is: Create a procedure to check commissions. Commissions higher than 0.35 can only be entered for employees with more than 15 years of experience. If the commission will be higher or practice will be lower, then an error will be printed. Take advantage of exceptions (Exception and Raise) to define an error message.
I wrote this, but there is an error:
PLS-00103 Encountered the symbol ">" when expecting one of following::= . ( # % ;
create or replace PROCEDURE PROVIZIA(num in number) IS
employee_id number;
com_pct employees.commission_pct%type;
begin
select commission_pct into com_pct from employees where employee_id = num;
if PRAX(employee_id) > 15 then
com_pct > 0.35;
else PRAX(employee_id) < 15 then
com_pct < 0.35;
end if;
exception when com_pct > 0.35 and PRAX(employee_id) < 15 then
dbms_output.put_line('error');
raise;
end PROVIZIA;
Can you please show me where i am making a mistake?
Thank you.
Suppose this is a test case (table and prax function which returns some number; I don't know which and why, so I made it so that it returns an "invalid" value for employee 1):
SQL> create table employees as
2 select 1 employee_id, 0.5 commission_pct from dual union all
3 select 2, 0.2 from dual;
Table created.
SQL> create or replace function prax(par_empid in number) return number is
2 begin
3 return case when par_empid = 1 then 10
4 else 50
5 end;
6 end prax;
7 /
Function created.
SQL> select employee_id, commission_pct, prax(employee_id) prax_result
2 from employees;
EMPLOYEE_ID COMMISSION_PCT PRAX_RESULT
----------- -------------- -----------
1 ,5 10 --> this combination is invalid
2 ,2 50 --> this is OK
SQL>
Procedure which raises an error if values are "wrong"; doesn't do anything otherwise (because you didn't say what to do in that case):
SQL> create or replace procedure provizia(num in number) is
2 com_pct employees.commission_pct%type;
3 l_err exception;
4 begin
5 select commission_pct
6 into com_pct
7 from employees
8 where employee_id = num;
9
10 if com_pct > 0.35 and prax(num) < 15 then
11 raise l_err;
12 end if;
13
14 exception
15 when l_err then
16 raise_application_error(-20000, 'Error');
17 end provizia;
18 /
Procedure created.
SQL>
Let's test it:
SQL> exec provizia(num => 1);
BEGIN provizia(num => 1); END;
*
ERROR at line 1:
ORA-20000: Error
ORA-06512: at "SYS.PROVIZIA", line 16
ORA-06512: at line 1
SQL> exec provizia(num => 2);
PL/SQL procedure successfully completed.
SQL>
Now that you have a working example, feel free to improve it.
com_ptc > 0.35
You can not write like this.Its return you true or false.
Look at the given pix.
If you use TOAD.exe then you will notify the runtime errors.
Look at the marked area.
Let's try this
CREATE OR REPLACE PROCEDURE PROVIZIA (num IN NUMBER)
IS
employee_id NUMBER;
com_pct employees.commission_pct%TYPE;
BEGIN
SELECT commission_pct
INTO com_pct
FROM employees
WHERE employee_id = num;
IF com_pct > 0.35 AND PRAX (employee_id) < 15
THEN
DBMS_OUTPUT.put_line ('error');
ELSE
DBMS_OUTPUT.put_line ('OK');
END IF;
END PROVIZIA;

plsql procedure doesn't do what i programmed it to do

my procedure is supposed to change 2 values but when i call it it shows the same values entered
code
CREATE OR REPLACE PROCEDURE commande_remise(pourcentage_rem IN Decimal,
c_client IN commande.code_client%type,
c_reg IN commande.reglement%type,
c_montantht IN OUT commande.montant_ht%type,
c_montantttc IN OUT commande.montant_ttc%type)
IS
c_ref commande.ref_commande%type;
BEGIN
SELECT COUNT(ref_commande) INTO c_ref FROM commande;
c_ref := c_ref + 1;
c_montantht := c_montantht-c_montantht*pourcentage_rem;
c_montantttc := c_montantttc-c_montantttc*pourcentage_rem;
INSERT INTO commande(ref_commande, code_client, reglement, montant_ht, montant_ttc)
VALUES(c_ref, c_client, c_reg, c_montantht, c_montantttc);
COMMIT;
END commande_remise;
/
procedure call
DECLARE
c_remise DECIMAL :=0.2;
c_code commande.code_client%type :=2;
c_reglement commande.reglement%type :='oui';
c_montantht commande.montant_ht%type :=3080.12;
c_montantttc commande.montant_ttc%type :=3530.56;
c_com commande%rowtype;
CURSOR c_cur IS SELECT ref_commande, code_client, reglement, montant_ht, montant_ttc FROM commande;
BEGIN
commande_remise(c_remise, c_code, c_reglement, c_montantht, c_montantttc);
OPEN c_cur;
LOOP
FETCH c_cur INTO c_com;
exit when c_cur%notfound;
dbms_output.put_line(c_com.ref_commande || ' ' || c_com.code_client || ' ' || c_com.reglement || ' ' || c_com.montant_ht || ' ' || c_com.montant_ttc);
END LOOP;
CLOSE c_cur;
END;
/
the values are c_montantht and c_montantttc
the result is the third:, please help.
Works for me (I'll tell you a secret later).
Table first:
SQL> create table commande
2 (ref_commande number,
3 code_client number,
4 reglement varchar2(10),
5 montant_ht number,
6 montant_ttc number);
Table created.
SQL>
Procedure:
SQL> CREATE OR REPLACE PROCEDURE commande_remise
2 (pourcentage_rem IN NUMBER,
3 c_client IN commande.code_client%type,
4 c_reg IN commande.reglement%type,
5 c_montantht IN OUT commande.montant_ht%type,
6 c_montantttc IN OUT commande.montant_ttc%type)
7 IS
8 c_ref commande.ref_commande%type;
9 BEGIN
10 SELECT COUNT(ref_commande) INTO c_ref FROM commande;
11 c_ref := c_ref + 1;
12 dbms_output.put_line('pourcentage_rem = ' || pourcentage_rem);
13 c_montantht := c_montantht - c_montantht * pourcentage_rem;
14 c_montantttc := c_montantttc - c_montantttc * pourcentage_rem;
15
16 INSERT INTO commande
17 (ref_commande, code_client, reglement, montant_ht, montant_ttc)
18 VALUES
19 (c_ref, c_client, c_reg, c_montantht, c_montantttc);
20 END commande_remise;
21 /
Procedure created.
SQL>
Anonymous PL/SQL block:
SQL> set serveroutput on;
SQL> DECLARE
2 c_remise NUMBER :=0.2;
3 c_code commande.code_client%type :=2;
4 c_reglement commande.reglement%type :='oui';
5 c_montantht commande.montant_ht%type :=3080.12;
6 c_montantttc commande.montant_ttc%type :=3530.56;
7 c_com commande%rowtype;
8 CURSOR c_cur IS SELECT ref_commande, code_client, reglement, montant_ht, montant_ttc FROM commande;
9 BEGIN
10 commande_remise(c_remise, c_code, c_reglement, c_montantht, c_montantttc);
11 OPEN c_cur;
12 LOOP
13 FETCH c_cur INTO c_com;
14 exit when c_cur%notfound;
15 dbms_output.put_line(c_com.ref_commande || ' ' || c_com.code_client
16 || ' ' || c_com.reglement || ' ' || c_com.montant_ht
17 || ' ' || c_com.montant_ttc);
18 END LOOP;
19 CLOSE c_cur;
20 END;
21 /
pourcentage_rem = ,2
1 2 oui 2464,096 2824,448
PL/SQL procedure successfully completed.
SQL>
Table contents:
SQL> select * From commande;
REF_COMMANDE CODE_CLIENT REGLEMENT MONTANT_HT MONTANT_TTC
------------ ----------- ---------- ---------- -----------
1 2 oui 2464,096 2824,448
SQL>
Looks OK, right?
The secret: don't use DECIMAL in
procedure's parameter declaration: pourcentage_rem IN Decimal
anonymous PL/SQL block's variable declaration: c_remise DECIMAL :=0.2;
Use NUMBER instead. Because, if you use DECIMAL, then procedure's line #12 displays
pourcentage_rem = 0
so - when you subtract something that is multiplied by zero, you subtract zero and get the input value itself.

Wrap select with an Oracle function

In my mind, I'm writing a function such that calling something like
select get_foo() from dual;
or
select * from table (get_foo);
returns the same result as
select * from foo;
So, I've got a function that compiles...
create or replace function get_foo return sys_refcursor as
rc_foo sys_refcursor;
begin
open rc_foo for 'select * from foo';
return rc_foo;
end;
but select get_foo() from dual returns 1 row.
((ID=1,NAME=Sarah1),(ID=2,NAME=Sarah2),(ID=3,NAME=Sarah3),)
whilst select * from table( get_foo() ) gives me ORA-22905.
How do I change the function definition and/or the call to get the desired outcome?
you use a pipelined function.
for example:
SQL> create table foo(id , name) as select rownum, 'Sarah'||rownum from dual connect by level <= 3;
Table created.
SQL> create or replace package pipeline_test
2 as
3 type foo_tab is table of foo%rowtype;
4 function get_foo
5 return foo_tab PIPELINED;
6 end;
7 /
Package created.
SQL> create or replace package body pipeline_test
2 as
3 function get_foo
4 return foo_tab PIPELINED
5 is
6 v_rc sys_refcursor;
7 t_foo foo_tab;
8
9 begin
10 open v_rc for select * from foo;
11 loop
12 fetch v_rc bulk collect into t_foo limit 100;
13 exit when t_foo.count = 0;
14 for idx in 1..t_foo.count
15 loop
16 pipe row(t_foo(idx));
17 end loop;
18 end loop;
19 end;
20 end;
21 /
Package body created.
SQL> select * from table(pipeline_test.get_foo());
ID NAME
---------- ---------------------------------------------
1 Sarah1
2 Sarah2
3 Sarah3

Resources