It says procedure created with compilation errors.
`create or replace procedure fact(n in number, r out number);
i number:=n
f number:=1;
begin
while(i>1) loop
f:=f*1;
i=i-1;
r=f;
end fact;`
Quite a few syntax errors; compare your code with mine, find the differences:
SQL> set serveroutput on
SQL> CREATE OR REPLACE PROCEDURE fact (n IN NUMBER, r OUT NUMBER)
2 AS
3 I NUMBER := n;
4 f NUMBER := 1;
5 BEGIN
6 WHILE (i > 1)
7 LOOP
8 f := f * i;
9 i := i - 1;
10 END LOOP;
11
12 r := f;
13 END fact;
14 /
Procedure created.
SQL>
SQL> DECLARE
2 l_out NUMBER;
3 BEGIN
4 fact (4, l_out);
5 DBMS_OUTPUT.put_line (l_out);
6 END;
7 /
24
PL/SQL procedure successfully completed.
SQL>
Though, why did you choose to create a procedure? A function might be more appropriate in this case:
SQL> CREATE OR REPLACE FUNCTION f_fact (n IN NUMBER)
2 RETURN NUMBER
3 IS
4 i NUMBER := n;
5 f NUMBER := 1;
6 BEGIN
7 WHILE (i > 1)
8 LOOP
9 f := f * i;
10 i := i - 1;
11 END LOOP;
12
13 RETURN f;
14 END;
15 /
Function created.
SQL>
SQL> SELECT f_fact (4) FROM DUAL;
F_FACT(4)
----------
24
SQL>
Related
I was trying to create a pipelined table function in PL/SQL but facing the below error. Is this an syntax error?
CREATE OR REPLACE FUNCTION FUNC_IDS(
IDS_IN IN VARCHAR2
) RETURN IDS_T
PIPELINED
IS
BEGIN
select * from dual;
return;
END func_ids;
Script Output:
Function FUNC_IDS compiled
LINE/COL ERROR
--------- -------------------------------------------------------------
0/0 PL/SQL: Compilation unit analysis terminated
3/10 PLS-00201: identifier 'IDS_T' must be declared
Errors: check compiler log
I missed to create the row and table types before creating the func. Have created them later as below and trying to create the function that gets input as a string of IDs and pipe out the individual IDs to another function.
CREATE TYPE TF_ROW AS OBJECT (ID NUMBER);
CREATE TYPE IDS_T IS TABLE OF TF_ROW;
create or replace function func_ids (ids_in in varchar2) return ids_t pipelined is
n_start pls_integer := 1;
n_end pls_integer := 1;
--
begin
loop
-- find the first and next comma in string
n_start := instr(ids_in, ',', n_start, 1);
n_end := instr(ids_in, ',', n_start, 2);
--
if (n_end <= 0) then
exit;
end if;
-- get the string and pipe it back out
pipe row (to_number(substr(ids_in, n_start+1, n_end - n_start - 1)));
-- ready for next one
n_start := n_end;
end loop;
return;
end func_ids;
Script Output:
Function FUNC_IDS compiled
LINE/COL ERROR
--------- -------------------------------------------------------------
22/5 PL/SQL: Statement ignored
22/15 PLS-00382: expression is of wrong type
Errors: check compiler log
What's wrong with the expression here?pipe row (to_number(substr(ids_in, n_start+1, n_end - n_start - 1)));
As you were told, IDS_T isn't declared.
Here's an example which works. See how I did it, do it yourself with your data.
Types:
SQL> create or replace type t_row is object (empno number, ename varchar2 (20));
2 /
Type created.
SQL> create or replace type t_tab is table of t_row;
2 /
Type created.
Function:
SQL> create or replace function func_ids (ids_in in varchar2)
2 return t_tab
3 pipelined
4 is
5 begin
6 for cur_r in (select empno, ename
7 from emp
8 where deptno = ids_in)
9 loop
10 pipe row (t_row (cur_r.empno, cur_r.ename));
11 end loop;
12
13 return;
14 end func_ids;
15 /
Function created.
Testing:
SQL> select * from table(func_ids (20));
EMPNO ENAME
---------- --------------------
7369 SMITH
7566 JONES
7788 SCOTT
7876 ADAMS
7902 FORD
SQL>
How to use the result returned by FUNC_IDS? I'm doing it using code you posted as a comment (the FUNC_ENAME function); I marked what you did wrong.
SQL> CREATE OR REPLACE FUNCTION func_ename (ids t_tab)
2 RETURN VARCHAR2
3 IS
4 l_tmp VARCHAR2 (100);
5 l_result VARCHAR2 (400);
6 BEGIN
7 l_result := ';';
8
9 FOR i IN ids.FIRST .. ids.LAST
10 LOOP
11 SELECT l.ename
12 INTO l_tmp
13 FROM emp l
14 WHERE l.empno = ids (i).empno; --> this line was wrong
15
16 l_result := l_result || l_tmp || ';';
17 END LOOP;
18
19 RETURN l_result;
20 END;
21 /
Function created.
SQL> SELECT func_ename (func_ids (10)) FROM DUAL;
FUNC_ENAME(FUNC_IDS(10))
------------------------------------------------------------------
;CLARK;KING;MILLER;
SQL>
Write a PL/SQL program using While Loop to display all DEPTNO,DNAME and LOC
from DEPT table. Assuming the difference between two deptno is 10.
I am beginer and i am very confuse to solve this query please help to solve this problem.
Something like this?
SQL> set serveroutput on
SQL> declare
2 i dept.deptno%type; -- loop counter
3 l_max_deptno dept.deptno%type; -- upper limit
4 l_dept_row dept%rowtype; -- will contain the whole DEPT table row
5 begin
6 -- MIN -> i (which will be the starting point); MAX -> l_max_deptno (which will be the end)
7 select min(deptno), max(deptno)
8 into i, l_max_deptno
9 from dept;
10
11 while i <= l_max_deptno
12 loop
13 -- select the whole row into L_DEPT_ROW
14 select *
15 into l_dept_row
16 from dept
17 where deptno = i;
18
19 dbms_output.put_line(l_dept_row.deptno ||' - '||
20 l_dept_row.dname ||' - '||
21 l_dept_row.loc);
22 -- increment counter by 10 (because, as you said, the difference is 10)
23 i := i + 10;
24 end loop;
25 end;
26 /
10 - ACCOUNTING - NEW YORK
20 - RESEARCH - DALLAS
30 - SALES - CHICAGO
40 - OPERATIONS - BOSTON
PL/SQL procedure successfully completed.
SQL>
Here is how you do what you asked for, but bear in mind this is not the optimum way to do it. if your target is to train your self on the While loop in PLSQL, then here you go.
DECLARE
CURSOR C_DEPTS
IS
SELECT DEPTNO, DNAME, LOC FROM DEPT;
V_DEPTNO VARCHAR2 (255);
V_DNAME VARCHAR2 (255);
V_LOC VARCHAR2 (255);
BEGIN
OPEN C_DEPTS;
FETCH C_DEPTS INTO V_DEPTNO, V_DNAME, V_LOC;
WHILE C_DEPTS%FOUND
LOOP
DBMS_OUTPUT.PUT_LINE ('DEPTNO = ' || V_DEPTNO);
DBMS_OUTPUT.PUT_LINE ('DNAME = ' || V_DNAME);
DBMS_OUTPUT.PUT_LINE ('LOC = ' || V_LOC);
FETCH C_DEPTS INTO V_DEPTNO, V_DNAME, V_LOC;
END LOOP;
END;
Okay, there must be a better way... Given constants:
create or replace PACKAGE time_conversion_cons AS
c_day_to_hr CONSTANT NUMBER := 24;
c_day_to_min CONSTANT NUMBER := 1440;
c_day_to_sec CONSTANT NUMBER := 86400;
c_hr_to_day CONSTANT NUMBER := .0417;
c_hr_to_min CONSTANT NUMBER := 60;
c_hr_to_sec CONSTANT NUMBER := 3600;
c_min_to_day CONSTANT NUMBER := .000694;
c_min_to_hr CONSTANT NUMBER := .0167;
c_min_to_sec CONSTANT NUMBER := 60;
c_sec_to_day CONSTANT NUMBER := .0001157;
c_sec_to_hr CONSTANT NUMBER := .000478;
c_sec_to_min CONSTANT NUMBER := .167;
END time_conversion_cons; -- this package spec compiles and runs fine.
For the input parameters (n, units), where units are (days, hrs, min's, seconds),
convert to the other three and display results.
The following anonymous block compiles, runs and solves the problem. Is there a way to avoid typing all of the BEGIN...END four times, once for each pair of parameters?
DECLARE
v_n1 NUMBER := 2.5;
v_u1 VARCHAR2(10) := 'days';
v_n2 NUMBER := 1.8;
v_u2 VARCHAR2(10) := 'hours';
v_n3 NUMBER := 13;
v_u3 VARCHAR2(10) := 'minutes';
v_n4 NUMBER := 720;
v_u4 VARCHAR2(10) := 'seconds';
BEGIN
pri(v_n1||' '||v_u1||' is '||
time_conversion_cons.c_day_to_hr * v_n1||' hours or '||
time_conversion_cons.c_day_to_min * v_n1||' minutes or '||
time_conversion_cons.c_day_to_sec * v_n1||' seconds.');
END;
SQL>
SQL> create or replace PACKAGE time_conversion_cons AS
2 type dim1 is table of number index by varchar2(10);
3 type dim2 is table of dim1 index by varchar2(10);
4 l_matrix dim2;
5
6 l_tags sys.odcivarchar2list := sys.odcivarchar2list('day','hr','min','sec');
7 end;
8 /
Package created.
SQL>
SQL> create or replace PACKAGE body time_conversion_cons AS
2 begin
3 l_matrix('day')('hr'):= 24;
4 l_matrix('day')('min'):= 1440;
5 l_matrix('day')('sec'):= 86400;
6 l_matrix('hr')('day'):= .0417;
7 l_matrix('hr')('min'):= 60;
8 l_matrix('hr')('sec'):= 3600;
9 l_matrix('min')('day'):= .000694;
10 l_matrix('min')('hr'):= .0167;
11 l_matrix('min')('sec'):= 60;
12 l_matrix('sec')('day'):= .0001157;
13 l_matrix('sec')('hr'):= .000478;
14 l_matrix('sec')('min'):= .167;
15 END;
16 /
Package body created.
SQL>
SQL>
SQL> set serverout on
SQL> DECLARE
2 v_n1 NUMBER := 2.5;
3 v_u1 VARCHAR2(10) := 'day';
4 BEGIN
5 for i in 1 .. time_conversion_cons.l_tags.count loop
6 if time_conversion_cons.l_tags(i) != v_u1 then
7 dbms_output.put_line(v_u1||' to '||time_conversion_cons.l_tags(i));
8 dbms_output.put_line(v_n1*time_conversion_cons.l_matrix(v_u1)(time_conversion_cons.l_tags(i)));
9 end if;
10 end loop;
11 END;
12 /
day to hr
60
day to min
3600
day to sec
216000
PL/SQL procedure successfully completed.
SQL>
SQL>
Just like some questions here, (a== 1 && a ==2 && a==3) had been proven that it can be evaluated to true in javascript and I'm just wondering if there is also a way in PL/SQL to evaluate it also to true.
Just for fun of course
SQL> create or replace
2 package pkg is
3 x int := 0;
4 end;
5 /
Package created.
SQL>
SQL> create or replace
2 function a return number is
3 begin
4 pkg.x := pkg.x + 1;
5 return pkg.x;
6 end;
7 /
Function created.
SQL>
SQL>
SQL> set serverout on
SQL> begin
2 if a = 1 and a = 2 and a = 3 then
3 dbms_output.put_line('BINGO!');
4 end if;
5 end;
6 /
BINGO!
PL/SQL procedure successfully completed.
I'm trying to run some procedures in parallel using dbms_jobs but i'm having some issues doing it. When trying to run below code, i'm getting this error
20:28:16 Info: Job #16 could not be executed. ORA-12011: execution of 1 jobs failed
ORA-06512: at "SYS.DBMS_IJOB", line 469
ORA-06512: at "SYS.DBMS_JOB", line 282
ORA-06512: at line 1
declare
ln_dummy number;
p_stdate CONSTANT DATE := '01-MAY-2012';
p_edate CONSTANT DATE := '31-MAY-2012';
p_cdate CONSTANT DATE := '09-FEB-2013';
p_key CONSTANT INTEGER:= 0;
p_ercode INTEGER;
p_erdesc VARCHAR2(200);
begin
COMMIT;
DBMS_JOB.SUBMIT(ln_dummy,'MY_PROC_1('''|| p_stdate ||''','''|| p_edate ||''','''|| p_cdate||''','''|| p_key ||''', :p_ercode, :p_erdesc: );');
COMMIT;
end;
/
p_ercode and p_erdesc is an out parameter in MY_PROC_1. If I try to comment it out the job runs without an issue.
My question is how can I run the job without commenting out p_ercode and p_erdesc in MY_PROC_1.
Also, is there a way to know which job is running and which job is already done? Something like an alert?
Maybe, this will work?
declare
ln_dummy number;
p_stdate CONSTANT DATE := '01-MAY-2012';
p_edate CONSTANT DATE := '31-MAY-2012';
p_cdate CONSTANT DATE := '09-FEB-2013';
p_key CONSTANT INTEGER:= 0;
begin
COMMIT;
DBMS_JOB.SUBMIT(ln_dummy,'
declare
p_ercode INTEGER;
p_erdesc VARCHAR2(200);
begin
MY_PROC_1('''|| p_stdate ||''','''|| p_edate ||''','''|| p_cdate||''','''|| p_key ||''', p_ercode, p_erdesc );
end;
');
COMMIT;
end;
if you want to log the outputs you can create a table:
SQL> create table log_table
2 (
3 job_id number,
4 start_time date,
5 end_time date,
6 retcode number,
7 retstr varchar2(4000)
8 )
9 /
Table created.
then execute the job. i've made a wrapper procedure just to make it a bit neater but you could put all of this in the job if you wanted.
SQL> create or replace procedure my_proc_1_job(
2 p_job number,
3 p_stdate date,
4 p_edate date,
5 p_cdate date,
6 p_key integer)
7 is
8 v_errcode integer;
9 v_errdesc varchar2(32767);
10 v_start_date date;
11 begin
12 v_start_date := sysdate;
13 my_proc_1(p_stdate, p_edate, p_cdate, p_key, v_errcode, v_errdesc);
14 insert into log_table (job_id, start_time, end_time, retcode, retstr)
15 values (p_job, v_start_date, sysdate, v_errcode, v_errdesc);
16 commit;
17 end;
18 /
Procedure created.
SQL> declare
2 ln_dummy number;
3 p_stdate CONSTANT varchar2(20) := '01-MAY-2012';
4 p_edate CONSTANT varchar2(20) := '31-MAY-2012';
5 p_cdate CONSTANT varchar2(20) := '09-FEB-2013';
6 p_key CONSTANT INTEGER:= 0;
7 begin
8 COMMIT;
9 DBMS_JOB.SUBMIT(
10 ln_dummy,
11 'my_proc_1_job(
12 JOB, to_date('''|| p_stdate ||''',''DD-MON-YYYY''),
13 to_date('''|| p_edate ||''',''DD-MON-YYYY''),
14 to_date('''|| p_cdate ||''',''DD-MON-YYYY''),
15 ' || p_key || ');');
16 COMMIT;
17 end;
18 /
PL/SQL procedure successfully completed.
SQL> select * from log_table;
JOB_ID START_TIM END_TIME RETCODE
---------- --------- --------- ----------
RETSTR
----------------------------------------------------------------------------------------------------
4 10-FEB-13 10-FEB-13 -1
failure
now all runs are recorded in LOG_TABLE.