Can not assign value to an IN OUT parameter - oracle

procedure check_startDate_is_grower_than_last_foo(startDate IN OUT DATE) as
last_foo_tsp DATE;
begin
select max(version_tsp) into last_foo_tsp from foo;
if startDate <= last_foo_tsp then
if trunc(startDate) = trunc(last_foo_tsp) then
startDate := (last_foo_tsp + 1/86400); -- +1 seg
else
raise_application_error(-20001, 'Blabla');
end if;
end if;
end;
I get an error:
PLS-00363: expression 'STARTDATE' cannot be used as an assignment target
What I'm doing wrong?

I don't know what you did wrong, because - it works for me.
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
SQL> select * from foo;
VERSION_TSP
-------------------
15.02.2022 00:00:00
SQL> create or replace
2 procedure p_check (startDate IN OUT DATE) as
3 last_foo_tsp DATE;
4 begin
5 select max(version_tsp) into last_foo_tsp from foo;
6 if startDate <= last_foo_tsp then
7 if trunc(startDate) = trunc(last_foo_tsp) then
8 startDate := (last_foo_tsp + 1/86400); -- +1 seg
9 else
10 raise_application_error(-20001, 'Blabla');
11 end if;
12 end if;
13 end;
14 /
Procedure created.
Testing:
SQL> set serveroutput on
SQL> declare
2 l_datum date := date '2022-02-15';
3 begin
4 p_check (l_datum);
5 dbms_output.put_line('result = ' || l_datum);
6 end;
7 /
result = 15.02.2022 00:00:01
PL/SQL procedure successfully completed.
SQL>

Related

PL/SQL Case WHEN with two constants followed by THEN expression

is it possible for somehow having a CASE with an OR option like below in PL/SQL ?
CASE selector
WHEN 'value1' OR 'value2' THEN S1;
WHEN 'value3' OR 'value4' THEN S2;
WHEN 'value3' THEN S3;
...
ELSE Sn; -- default case
END CASE;
I'd rather use IN:
SQL> declare
2 selector varchar2(20);
3 result varchar2(20);
4 begin
5 selector := '10';
6
7 result := case when selector in ('10', '20') then 's1'
8 when selector in ('30', '40') then 's2'
9 else 'sn'
10 end;
11 dbms_output.put_line('Result = ' || result);
12 end;
13 /
Result = s1
PL/SQL procedure successfully completed.
SQL>
You can use OR, though:
SQL> declare
2 selector varchar2(20);
3 result varchar2(20);
4 begin
5 selector := '10';
6
7 result := case when selector = '10' or selector = '20' then 's1'
8 when selector = '30' or selector = '40' then 's2'
9 else 'sn'
10 end;
11 dbms_output.put_line('Result = ' || result);
12 end;
13 /
Result = s1
PL/SQL procedure successfully completed.
SQL>

PL/SQL simple task

I want to create a procedure whith two arguments. It should check if the arguments are values of family table and if both are not the same value.
I planned this code but I noted it doesn't work
create or replace procedure Compare(first_value values.value%type, second_value values.value%type)
as
begin
if second_value not exists(select values from family) then
dbms.output.put_line('The second values doesn't exist');
else if first_value = second_value then
dbms.output.put_line('Both values are the same');
else
dbms.output.put_line('Great Job');
end if;
end;
/
I'll appreciate any help.
Here's one option.
SQL> set serveroutput on
Sample data:
SQL> select * from family;
C_VALUES
--------
Little
Foot
Procedure:
SQL> create or replace procedure p_compare
2 (par_value_1 in family.c_values%type,
3 par_value_2 in family.c_values%type
4 )
5 as
6 l_cnt_1 number;
7 l_cnt_2 number;
8 begin
9 select count(*)
10 into l_cnt_1
11 from family
12 where c_values = par_value_1;
13
14 select count(*)
15 into l_cnt_2
16 from family
17 where c_values = par_value_2;
18
19 if l_cnt_1 = 0 then
20 dbms_output.put_line('The first value does not exist');
21 elsif l_cnt_2 = 0 then
22 dbms_output.put_line('The second value does not exist');
23 elsif par_value_1 = par_value_2 then
24 dbms_output.put_line('Both values are the same');
25 else
26 dbms_output.put_line('Great job');
27 end if;
28 end;
29 /
Procedure created.
Testing:
SQL> exec p_compare('Little', 'Foot');
Great job
PL/SQL procedure successfully completed.
SQL> exec p_compare('Little', 'Little');
Both values are the same
PL/SQL procedure successfully completed.
SQL> exec p_compare('Big', 'Foot');
The first value does not exist
PL/SQL procedure successfully completed.
SQL>
Here is a not so well written, but somehow alternative take on the task:
CREATE OR REPLACE PROCEDURE COMPARE(FIRST_VALUE VALUES.VALUE%TYPE,
SECOND_VALUE VALUES.VALUE%TYPE)
AS
l_message VARCHAR2(40);
BEGIN
SELECT CASE WHEN test_val < 2 THEN 'The first value does not exist'
WHEN test_val < 3 THEN 'The second value does not exist'
WHEN first_value = second_value THEN 'Both values are the same'
ELSE 'Great job'
END
INTO l_message
FROM (SELECT NVL(SUM(val),0) AS test_val
FROM (SELECT 2 AS val
FROM family
WHERE val = first_value
AND ROWNUM = 1
UNION ALL
SELECT 1 AS val
FROM family
WHERE val = second_value
AND ROWNUM = 1));
DBMS_OUTPUT.PUT_LINE(l_message);
END;
/

pipelined function with if statement

I'd like to create a function to retrieve valid years for each record. I've got columns valid_from and valid_to in table.
For example valid_from = 2018-04-30 and valid_to = 2020-06-30; function should result three values: 2018, 2019, 2020.
I created a type and a function but it isn't working at all ...
create or replace type t_years is table of varchar2(4);
create or replace function func_year(d_from date, d_to date) return t_years pipelined
is
v_date date := '21/12/31 00:00:00';
max_date date := '99/12/30 00:00:00';
begin
for x in 1..2 loop
if d_from <= add_months(v_date,-1*12) AND (add_months(d_to,-1*12) >= v_date OR add_months(d_to,-1*12) = max_date) then return '2020';
elsif d_from <= add_months(v_date,-2*12) AND (add_months(d_to,-2*12) >= v_date OR add_months(d_to,-2*12) = max_date) then return '2019';
end if;
pipe row(x);
end loop;
return;
end;
Here's how:
SQL> CREATE OR REPLACE TYPE t_years IS TABLE OF VARCHAR2 (4);
2 /
Type created.
SQL> CREATE OR REPLACE FUNCTION func_year (d_from IN DATE, d_to IN DATE)
2 RETURN t_years
3 PIPELINED
4 IS
5 BEGIN
6 FOR i IN EXTRACT (YEAR FROM d_from) .. EXTRACT (YEAR FROM d_to)
7 LOOP
8 PIPE ROW (i);
9 END LOOP;
10
11 RETURN;
12 END;
13 /
Function created.
SQL> SELECT func_year (DATE '2019-01-01', DATE '2021-01-01') FROM DUAL;
FUNC_YEAR(DATE'2019-01-01',DATE'2021-01-01')
----------------------------------------------------------------------------------------------------
T_YEARS('2019', '2020', '2021')
SQL>
Or
SQL> SELECT * FROM TABLE (func_year (DATE '2019-01-01', DATE '2021-01-01'));
COLU
----
2019
2020
2021
SQL>

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;

converting a plsql code into a function

I have this piece of code which I want to convert into a function , and call the function in a select statement by passing vendor_site_id from ap_supplier_sites_all. so that I can get the value of vendor_number i.e segment1 of ap_suppliers . here in this piece of code , I have a login to fetch first 6 digits from the column attribute52 of DFF table gecm_dff_ext .
DECLARE
v_ret_val VARCHAR2(30);
v_sup_gsl VARCHAR2(30);
v_vendor_id NUMBER;
BEGIN
v_vendor_id := '${PO.H_VENDOR_ID}';--> vendor_id column from ap_suppliers
IF <condition> = 'Y'
THEN
BEGIN
SELECT SUBSTR(ATTRIBUTE52,1,6)
INTO v_sup_gsl
FROM gecm_dff_ext
WHERE primary_table ='AP_SUPPLIER_SITES_ALL'
AND primary_key = '${PO.H_VENDOR_SITE_ID}';--> This value should be vendor_site_id from ap_supplier_sites_all table
EXCEPTION
WHEN OTHERS THEN
v_sup_gsl := NULL;
END;
BEGIN
IF v_sup_gsl IS NOT NULL THEN
SELECT segment1
INTO v_ret_val
FROM ap_suppliers
WHERE segment1 = v_sup_gsl;
END IF;
EXCEPTION
WHEN OTHERS THEN
v_ret_val := '';
END;
END IF;
IF v_sup_gsl IS NULL THEN
BEGIN
SELECT SEGMENT1
INTO v_ret_val
FROM ap_suppliers
WHERE vendor_id=v_vendor_id;
EXCEPTION
WHEN OTHERS THEN
v_ret_val := '';
END;
END IF;
:return_value:=v_ret_val;
END;
This is a simplified example: the following SELECT returns department name for a certain department number:
SQL> select dname
2 from dept
3 where deptno = &par_deptno;
Enter value for par_deptno: 10
DNAME
--------------
ACCOUNTING
SQL>
So, how to convert it to a function? By using a proper syntax, declaring a return variable, fetching into it and - returning the result:
SQL> create or replace function f_test (par_deptno in dept.deptno%type)
2 return dept.dname%type
3 is
4 retval dept.dname%type;
5 begin
6 select dname
7 into retval
8 from dept
9 where deptno = par_deptno;
10
11 return retval;
12 exception
13 when no_data_found then
14 return null;
15 end;
16 /
Function created.
SQL> select f_test(10) from dual;
F_TEST(10)
---------------------------------------------------------------------------
ACCOUNTING
SQL> select f_test(999) from dual;
F_TEST(999)
---------------------------------------------------------------------------
SQL>
This is what you should do. It seems that you are returning the v_ret_val, so - your code might look like this:
create or replace function f_test (par_vendor_id po.h_vendor_id%type)
return ap_suppliers.segment1%type
is
v_ret_val ap_suppliers.segment1%type;
begin
if <condition> = 'Y' then
...
end if;
return v_ret_val;
end;

Resources