Compare two value in Oracle Procedure - oracle

i'm very noob at that, can you help me? I have to see if cash>=price and cash is taken from "portafoglio" from "studente" table and price is taken from "costo" from "corso" table but it gave me several error
CREATE OR REPLACE FUNCTION PAGA_CORSO
(
MAT IN NUMBER
, COR IN NUMBER
, DAT IN DATE
, cash DOUBLE PRECISION
, price DOUBLE PRECISION
) RETURN BOOLEAN AS
BEGIN
SELECT portafoglio
INTO cash
FROM studente
WHERE matricola=MAT;
SELECT costo
INTO price
FROM corso
WHERE codicecorso=COR;
IF cash >= price THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
END PAGA_CORSO;
Thanks!

You are missing OUT clauses, because you want to return values "out" of the function,
SQL> CREATE OR REPLACE FUNCTION PAGA_CORSO
2 (
3 MAT IN NUMBER
4 , COR IN NUMBER
5 , DAT IN DATE
6 , cash DOUBLE PRECISION
7 , price DOUBLE PRECISION
8 ) RETURN BOOLEAN AS
9 BEGIN
10 SELECT sal
11 INTO cash
12 FROM emp
13 WHERE empno=MAT;
14
15 SELECT deptno
16 INTO price
17 FROM dept
18 WHERE deptno=COR;
19
20 IF cash >= price THEN
21 RETURN FALSE;
22 ELSE
23 RETURN TRUE;
24 END IF;
25 END PAGA_CORSO;
26 /
Warning: Function created with compilation errors.
SQL>
SQL> sho err
Errors for FUNCTION PAGA_CORSO:
LINE/COL ERROR
-------- -----------------------------------------------------------------
10/5 PL/SQL: SQL Statement ignored
11/10 PLS-00403: expression 'CASH' cannot be used as an INTO-target of
a SELECT/FETCH statement
12/5 PL/SQL: ORA-00904: : invalid identifier
15/5 PL/SQL: SQL Statement ignored
16/10 PLS-00403: expression 'PRICE' cannot be used as an INTO-target of
a SELECT/FETCH statement
17/5 PL/SQL: ORA-00904: : invalid identifier
Now we add OUT to the definition
SQL> CREATE OR REPLACE FUNCTION PAGA_CORSO
2 (
3 MAT IN NUMBER
4 , COR IN NUMBER
5 , DAT IN DATE
6 , cash out DOUBLE PRECISION
7 , price out DOUBLE PRECISION
8 ) RETURN BOOLEAN AS
9 BEGIN
10 SELECT sal
11 INTO cash
12 FROM emp
13 WHERE empno=MAT;
14
15 SELECT deptno
16 INTO price
17 FROM dept
18 WHERE deptno=COR;
19
20 IF cash >= price THEN
21 RETURN FALSE;
22 ELSE
23 RETURN TRUE;
24 END IF;
25 END PAGA_CORSO;
26 /
Function created.
Also, "double precision" is rare - I'd suggest you probably just want to go with NUMBER.

Related

raise_application_error reuse of the error

I was wondering if theres a way in which I can decide that from "this day on" a user-defined error can act as a resource I can use over and over.
For example->
Raise_Application_Error (-20343, 'The balance is too low.');
So basically if I can use -20343 as key word(error code) and use again in a different procedure instead of raising it again and again..,
Is that possible?
Well, you'll have to raise it, somehow, Oracle can't know what you want to do if balance is too low.
Maybe you could create your own table of exceptions, e.g.
SQL> select * from my_exception;
ERR_CODE ERR_NAM ERR_MESSAGE
---------- ------- ------------------------------
-20343 bal_low Balance is too low
-20344 name_s Name can not begin with an "S"
Function accepts error code and returns message:
SQL> create or replace function f_myerr (par_err_code in my_exception.err_code%type)
2 return my_exception.err_message%type
3 is
4 retval my_exception.err_message%type;
5 begin
6 select err_message
7 into retval
8 from my_exception
9 where err_code = par_err_code;
10 return retval;
11 exception
12 when no_data_found then
13 return 'Exception does not exist';
14 end;
15 /
Function created.
This piece of code simulates "balance too low" error:
SQL> declare
2 l_balance number;
3 bal_low exception;
4 begin
5 select sal into l_balance
6 from emp
7 where ename = 'JONES';
8
9 if l_balance < 5000 then
10 raise bal_low;
11 end if;
12
13 exception
14 when bal_low then
15 raise_application_error(-20343, f_myerr(-20343));
16 end;
17 /
declare
*
ERROR at line 1:
ORA-20343: Balance is too low
ORA-06512: at line 15
SQL>
Another PL/SQL procedure might also find out that balance is too low, but you'd have to repeat such a code again, I'm afraid.
You can modify that code (i.e. table, function) to better suit your needs, but - that's what I understood for what you said so far.

PL/SQL CURRENT_DATE if NULL

I need some help for figuring out how to use the CURRENT_DATE if the p_start_time is NULL when doing an insert.
The code below is what I have figured out so far (except for the insert statement). The code I need help for is the last code block.
Using PL/SQL btw.
create or replace procedure BEGIN_TRIP_SP (
p_trip_id OUT INTEGER, -- an output parameter
p_bicycle_id IN INTEGER, -- Must not be NULL. Must match value value in BC_BICYCLE and BC_DOCK tables.
p_start_time IN DATE, -- If NULL, use CURRENT_DATE system date value
p_membership_id IN INTEGER -- Must not be NULL. Must match value in BC_MEMBERSHIP table.
)
IS
lv_membership_id_exist INTEGER;
lv_bicycle_id_exist INTEGER;
lv_Error_Message VARCHAR2(200);
ex_Exception EXCEPTION;
BEGIN
IF p_bicycle_id IS NULL THEN
lv_Error_Message := 'Missing mandatory value for bicycle id in BEGIN_TRIP_SP. No trip added.';
RAISE ex_Exception;
END IF;
IF p_start_time IS NULL THEN
NVL(trip_start_time, '08-03-2022')
END IF;
INSERT INTO bc_trip (
Trip_id,
Bicycle_id,
Trip_start_time,
Membership_id
)
VALUES (
p_trip_id,
p_bicycle_id,
NVL(p_start_time, current_date),
p_membership_id
);
See if this helps; I presumed trip_id is somehow automatically generated so you'll be just returning its value to the caller.
Sample table:
SQL> CREATE TABLE bc_trip
2 (
3 trip_id NUMBER GENERATED ALWAYS AS IDENTITY,
4 bicycle_id NUMBER,
5 trip_start_time DATE,
6 membership_id NUMBER
7 );
Table created.
Procedure:
SQL> CREATE OR REPLACE PROCEDURE begin_trip_sp
2 (p_trip_id OUT INTEGER, -- an output parameter
3 p_bicycle_id IN INTEGER, -- Must not be NULL. Must match value value in BC_BICYCLE and BC_DOCK tables.
4 p_start_time IN DATE, -- If NULL, use CURRENT_DATE system date value
5 p_membership_id IN INTEGER -- Must not be NULL. Must match value in BC_MEMBERSHIP table.
6 )
7 IS
8 BEGIN
9 IF p_bicycle_id IS NULL
10 THEN
11 raise_application_error (
12 -20000,
13 'Missing mandatory value for bicycle id in BEGIN_TRIP_SP. No trip added.');
14 ELSE
15 INSERT INTO bc_trip (bicycle_id, trip_start_time, membership_id)
16 VALUES (p_bicycle_id,
17 NVL (p_start_time, CURRENT_DATE),
18 p_membership_id)
19 RETURNING trip_id
20 INTO p_trip_id;
21 END IF;
22 END;
23 /
Procedure created.
Testing:
SQL> SET SERVEROUTPUT ON
SQL> DECLARE
2 l_trip_id NUMBER;
3 BEGIN
4 begin_trip_sp (l_trip_id,
5 1,
6 NULL,
7 100);
8 DBMS_OUTPUT.put_line ('Inserted trip ID = ' || l_trip_id);
9 END;
10 /
Inserted trip ID = 1
PL/SQL procedure successfully completed.
What if there's no P_BICYCLE_ID?
SQL> l5
5* 1,
SQL> c/1/null/
5* null,
SQL> /
DECLARE
*
ERROR at line 1:
ORA-20000: Missing mandatory value for bicycle id in BEGIN_TRIP_SP. No trip
added.
ORA-06512: at "DP_4005.BEGIN_TRIP_SP", line 11
ORA-06512: at line 4
SQL>
Result is
SQL> SELECT * FROM bc_trip;
TRIP_ID BICYCLE_ID TRIP_START MEMBERSHIP_ID
---------- ---------- ---------- -------------
1 1 08.03.2022 100
SQL>
Just write default value for that parameter:
create or replace procedure BEGIN_TRIP_SP (
p_trip_id OUT INTEGER,
p_bicycle_id IN INTEGER,
p_start_time IN DATE DEFAULT sysdate,--if the parameter is not given it will take sysdate (current date)
p_membership_id IN INTEGER
)...

plsql error " Encountered the symbol ( when expecting one of the following: :-) " on line "drug_name IN CHAR(255),"

CREATE OR REPLACE
PROCEDURE ADD_DRUG_TO_ORDER
(
order_id IN INT,
drug_name IN CHAR(255),
quantity IN INT
)
AS
drug MEDICINE%ROWTYPE;
insufficient_quantity EXCEPTION;
BEGIN
SELECT *
INTO drug
FROM MEDICINE
WHERE 'drug_name' = drug_name;
Cause of error you reported is that parameters can't have size, so it is not char(255) but char. However, you'd rather use varchar2 (char is right-padded to its full size by spaces).
Other than that, you should not name parameters as column names because you'll get unexpected results.
Something like this might be a starting point for you:
SQL> create or replace procedure add_drug_to_order
2 (par__order_id in int,
3 par_drug_name in varchar2,
4 par_quantity in int
5 )
6 is
7 l_drug medicine%rowtype;
8 begin
9 select *
10 into l_drug
11 from medicine
12 where drug_name = par_drug_name;
13 end;
14 /
Procedure created.
SQL>

declaring cursor in compound trigger pl/sql

When I ran this code, I've got this error:
PLS-00103: Encountered the symbol "IS" when expecting one of the following:
:= . ( # % ; not null range default character.
I think something wrong with declaration section but the same declaration works in a row-lvl trigger, so I'm confused is this permitted in compound triggers at all. I couldn't find the examples, so I ask you here.
create or replace trigger ivan_moving
for update of country on clients
compound trigger
declare
n_country clients.country%type;
min_date clients.bday%type;
cursor ivans is select* from clients where fname like 'Ivan%' and Bday > (select min(Bday) from clients where fname like 'Ivan%');
client_ivan ivans%rowtype;
before statement is
min_date = select Bday from clients where fname like 'Ivan%' and Bday = (select min(Bday) from clients where fname like 'Ivan%');
end before statement;
after each row is
begin
if :OLD.country <> :NEW.country and fname = 'Ivan%' and bday = min_date
n_country := :new.country;
end if;
end after each row;
after statement is
begin
open ivans;
loop
fetch ivans into client_ivan;
exit when ivans%notfound;
update clients set country = n_country where id = client_ivan.id;
end loop;
close ivans;
end after statement;
end ivan_moving;
/
Quite a few mistakes, e.g.
you shouldn't use declare
in PL/SQL, SELECT requires INTO
it is not = 'Ivan%' but like 'Ivan%'
it seems you "forgot" to specify :new for some columns
There might be some other errors I didn't mention. I don't know if trigger does what you intended, but - at least, syntax errors are now fixed.
SQL> create or replace trigger ivan_moving
2 for update of country on clients
3 compound trigger
4 n_country clients.country%type;
5 min_date clients.bday%type;
6 cursor ivans is
7 select * from clients
8 where fname like 'Ivan%'
9 and bday > min_date;
10 client_ivan ivans%rowtype;
11
12 before statement is
13 begin
14 select bday
15 into min_date
16 from clients
17 where fname like 'Ivan%'
18 and bday = (select min(bday)
19 from clients
20 where fname like 'Ivan%');
21 end before statement;
22
23 after each row is
24 begin
25 if :old.country <> :new.country
26 and :new.fname like 'Ivan%'
27 and :new.bday = min_date
28 then
29 n_country := :new.country;
30 end if;
31 end after each row;
32
33 after statement is
34 begin
35 open ivans;
36 loop
37 fetch ivans into client_ivan;
38 exit when ivans%notfound;
39 update clients set country = n_country where id = client_ivan.id;
40 end loop;
41 close ivans;
42 end after statement;
43
44 end ivan_moving;
45 /
Trigger created.

Compare values in each column of two Oracle Types

I've been playing around with the pluto-test-framework today, and I'd like to get some existing functions into a test harness with it.
I have lots of functions with this type of specification.
FUNCTION DO_SOME_STUFF (pOldSchedule IN SCHEDULE_OBJ,
pNewSchedule OUT SCHEDULE_OBJ,
pLoggerContext IN OUT LOGGER_CONTEXT_OBJ)
RETURN NUMBER;
It takes pOldSchedule, does some stuff to it, and then returns pNewSchedule. The logger_context just does logging.
As part of a test, I'd like to be able to compare the values in each of the columns of the type, without having to write individual IF statements.
It'll need to return boolean to signify whether or not pOldSchedule and pNewSchedule match.
Any ideas?
Straightforward equality tests work with nested tables:
SQL> declare
2 type nt is table of number;
3 nt1 nt;
4 nt2 nt;
5 nt3 nt;
6 begin
7 nt1 := nt(1,2,3);
8 nt2 := nt(1,2,3);
9 if nt1 = nt2 then
10 dbms_output.put_line('NT2 is the same nested table as NT1');
11 else
12 dbms_output.put_line('NT2 is a different nested table from NT1');
13 end if;
14 nt2 := nt(1,2,3,4);
15 if nt1 = nt3 then
16 dbms_output.put_line('NT3 is the same nested table as NT1');
17 else
18 dbms_output.put_line('E3 is a different nested table from NT1');
19 end if;
20 end;
21 /
NT2 is the same nested table as NT1
E3 is a different nested table from NT1
PL/SQL procedure successfully completed.
SQL>
However the same is not true of full-on objects:
SQL> create or replace type new_emp as object (
2 ename varchar2(10)
3 , sal number
4 , deptno number
5 , job varchar2(10))
6 /
Type created.
SQL> declare
2 e1 new_emp;
3 e2 new_emp;
4 begin
5 e1 := new_emp('KESTELYN', 3700, 30, 'MARKETING');
6 e2 := new_emp('KESTELYN', 3700, 30, 'MARKETING');
7 if e1 = e2 then
8 dbms_output.put_line('E2 is the same as E1');
9 else
10 dbms_output.put_line('E2 is different from E1');
11 end if;
12 end;
13 /
if e1 = e2 then
*
ERROR at line 7:
ORA-06550: line 7, column 11:
PLS-00526: A MAP or ORDER function is required for comparing objects in PL/SQL.
SQL>
We need to explicitly define a member function for executing comparisons. So here is the same object with a MAP function. The example implementation generates a hashed string, which is useful if we want to store the value for later comparison, but it could just return the concatenated string (especially as EXECUTE on DBMS_CRYPTO is not granted by default). The NVL() functions are necessary to avoid (null, value) and (value, null) being evaluated as equal. There is the always a risk when using magic values, so we need to choose them carefully.
SQL> create or replace type new_emp as object (
2 ename varchar2(10)
3 , sal number
4 , deptno number
5 , job varchar2(10)
6 , map member function equals return raw)
7 /
Type created.
SQL> create or replace type body new_emp as
2 map member function equals return raw
3 is
4 begin
5 return dbms_crypto.hash(
6 utl_raw.cast_to_raw(nvl(self.ename,'***')||
7 nvl(self.sal,-99)||
8 nvl(self.deptno,-99)||
9 nvl(self.job,'***')
10 )
11 , 1);
12 end equals;
13 end;
14 /
Type body created.
SQL>
Now we have a basis for comparing instances of our objects:
SQL> declare
2 e1 new_emp;
3 e2 new_emp;
4 begin
5 e1 := new_emp('KESTELYN', 3700, 30, 'MARKETING');
6 e2 := new_emp('KESTELYN', 3700, 30, 'MARKETING');
7 if e1 = e2 then
8 dbms_output.put_line('E2 is the same as E1');
9 else
10 dbms_output.put_line('E2 is different from E1');
11 end if;
12 end;
13 /
E2 is the same as E1
PL/SQL procedure successfully completed.
SQL>
You might be wondering why Oracle doesn't do this by default. Well, the TYPE implemntation only allows one comparison method (if we have a MAP function we cannot have an ORDER function) so we need to have the capability to choose our own definition of equality. For instance, a type called rectangle might have a MAP function called area() which returns self.width * self.length.

Resources