PL/SQL functions [duplicate] - plsql

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Homework on PL/SQL FUNCTIONS
plsql functions
Function:
function to Display_Employee_Name_In_Uppercase that accepts the Employee_ID from the Empoyees table and returns the first and the last name of the employee in uppercase.
Write a small PL/SQL program to display the names of the employees whose Employee_IDs are 107, 200 and 205.
this is what I have done I didnt know how to complete it
can help ?
CREATE OR REPLACE FUNCTION disp (emp_id in varchar20) return emp_name
select into emp_name
fname||lname
from employees
where employee_id=emp_id
END disp ;

Something like this...
CREATE OR REPLACE
FUNCTION Fn_Display(p_empId IN VARCHAR2)
RETURN VARCHAR2
IS
empName VARCHAR2(100);
BEGIN
BEGIN
SELECT UPPER(first_name || ' ' || last_name)
INTO empName
FROM Employees
WHERE employee_id = p_empId;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE NO_DATA_FOUND
END;
RETURN empName;
END Fn_Display;
You can call this function wherever you want. here is a sample...
DECLARE
empId VARCHAR2(100);
empName VARCHAR2(100);
BEGIN
empId := &ENTER_EMPLOYEE_ID;
empName := Fn_Display(empId);
DBMS_OUTPUT.PUT_LINE('Employee Name: '||empName);
END;

You could try this code, maybe this one works for you:
CREATE OR REPLACE FUNCTION disp (emp_id in varchar2) return varchar2 IS
emp_name varchar2(256);
BEGIN
select UPPER(fname || ' ' || lname)
into emp_name
from employees
where employee_id = emp_id;
return emp_name;
END disp;

Related

PL/SQL: I get expression 'I' cannot be used as an assignment target

My code:
create table info(str varchar2(30));
declare
cursor c(job emp_ast.job_id%type, dep emp_ast.department_id%type) is select employee_id
from emp_ast
where job_id=job and department_id=dep;
type t_job is table of emp_ast.job_id%type;
t t_job:=t_job();
emp emp_ast.employee_id%type;
i number(3);
begin
select job_id
bulk collect into t
from emp_ast;
for i in 10..270 loop
for j in 1..t.count loop
open c(i, t(j));
loop
fetch c into emp;
insert into info
values (i||' '||t(j)||' '||emp);
exit when c%notfound;
end loop;
i:=i+10;
end loop;
end loop;
end;
/
I get "expression 'I' cannot be used as an assignment target", reffering to the line where I increment i by 10. I am trying to save the department_id, employee_id and job_id as a string in a table for each department and each job.
At the point where you get that message, i refers to the loop control variable i defined in the line for i in 10..270 loop, not the int(3) variable defined earlier. In PL/SQL a loop definition defines a variable which is only accessible inside the loop, and which you cannot alter. I suggest you change the name of one or the other to make them unique.
EDIT
PL/SQL doesn't provide a way to step by more than 1 in a computed FOR loop. Instead, you will need to compute the desired department number value within the loop:
DECLARE
CURSOR c(job EMP_AST.JOB_ID%TYPE,
dep EMP_AST.DEPARTMENT_ID%TYPE)
IS SELECT EMPLOYEE_ID
FROM EMP_AST
WHERE JOB_ID = job AND
DEPARTMENT_ID = dep;
TYPE t_job IS TABLE OF EMP_AST.JOB_ID%TYPE;
t t_job := t_job();
emp EMP_AST.EMPLOYEE_ID%TYPE;
nDepartment NUMBER;
BEGIN
SELECT job_id
BULK COLLECT INTO t
FROM EMP_AST;
FOR i IN 1..27 LOOP
nDepartment := i * 10;
FOR j IN 1..t.COUNT LOOP
OPEN c(t(j), nDepartment);
LOOP
FETCH c INTO emp;
INSERT INTO info
VALUES (nDepartment || ' ' || t(j) || ' ' || emp);
EXIT WHEN c%notfound;
END LOOP; -- cursor c
CLOSE c;
END LOOP; -- j
END LOOP; -- i
END;
/
Note that in the code above the nDepartment value is computed within the i loop, which now increments from 1 to 27 instead of going from 10 to 270.

Using parameters in procedures

I need to create a procedure that receives as a parameter a month and a year.
Inside the procedure I need to have a query to retrieve some values, that will have to take in account the parameters received.
create or replace procedure GET_REVS(MONTH in VARCHAR2,YEAR in varchar2) is
SELECT
*
FROM
REVENUS_TABLE
WHERE
Y_CODE IN ('YEAR')
AND M_CODE IN ()
Now, M_CODE should have the values since the start of the year until the month received by parameter.
Example if i receive in as parameter for the month a 4 i want my select to like this AND M_CODE IN ('1','2','3','4')
But if i receive MONTH = 3.. i need the select to have AND M_CODE IN ('1','2','3')
So what is the best way to do the procedure in order to be able to do that?
Thanks a lot
You could cast both M_CODE and MONTH as numbers and use BETWEEN operator or just <=:
CREATE OR REPLACE PROCEDURE get_revs(month IN VARCHAR2, year IN VARCHAR2) IS
BEGIN
....
SELECT *
FROM revenus_table
WHERE y_code = year
AND TO_NUMBER(m_code) BETWEEN 1 AND TO_NUMBER(month);
...
END;
You can do some thing like below example to make your procedure more dynamic
CREATE OR REPLACE PROCEDURE get_revs (
MONTH IN VARCHAR2,
YEAR IN VARCHAR2
)
IS
variable_name table_name%ROWTYPE;
v_sql VARCHAR2 (1000)
:= 'SELECT * FROM REVENUS_TABLE WHERE Y_CODE IN ('
|| MONTH
|| ')';
BEGIN
IF MONTH = 4 THEN
v_sql := v_sql || ' and M_CODE IN (''1'',''2'',''3'',''4'')';
END IF;
IF MONTH = 3 THEN
v_sql := v_sql || 'and M_CODE IN (''1'',''2'',''3'')';
END IF;
EXECUTE IMMEDIATE v_sql
INTO variable_name;
END;
Just an alternative to think about.
CREATE OR REPLACE PROCEDURE get_revs(month IN VARCHAR2, year IN VARCHAR2) IS
lv_in_clause VARCHAR2(100 CHAR);
p_ref sys_refcursor;
BEGIN
SELECT 'IN ('
||WMSYS.WM_CONCAT(A.NUM)
||')'
INTO lv_in_clause
FROM
(SELECT ''''
||LEVEL
||'''' NUM,
1 ID1
FROM DUAL
CONNECT BY LEVEL < to_number(MONTH)
)A
GROUP BY a.ID1;
OPEN p_ref FOR 'SELECT *
FROM revenus_table
WHERE y_code = '|| year
||' AND m_code '||lv_in_clause;
END;

Create table and then insert data into the new table from another table

I am creating one table name emp_inforamtion with checking that table is exist in database or not ,and if not then creating table then inserting the data from bank table in to emp_information table.
DECLARE
ncount NUMBER;
v_sql VARCHAR2(4000);
CURSOR c1
IS
SELECT bank_code,
center_code,
bank_name,
logo
FROM bank
WHERE bank_code ='607143';
BEGIN
SELECT COUNT(1) INTO ncount FROM tab WHERE tname LIKE '%EMP_INFORMATION%';
IF (ncount <= 0) THEN
DBMS_OUTPUT.PUT_LINE (ncount || 'count');
BEGIN
v_sql :=' CREATE TABLE EMP_INFORMATION
(
emp_id VARCHAR2(3),
emp_name VARCHAR2(20),
emp_salary VARCHAR2(3),
emp_department VARCHAR2(3)
)';
EXECUTE immediate v_sql;
COMMIT;
BEGIN
FOR i IN c1
LOOP
INSERT
INTO EMP_INFORMATION
(
emp_id,
emp_name,
emp_salary,
emp_department
)
VALUES
(
i.bank_code,
i.bank_name,
i.center_code,
i.logo
);
END LOOP;
END;
END;
END IF;
end;
/
found below error after executing the above cursor:
ORA-06550: line 30, column 16: PL/SQL: ORA-00942: table or view does not exist
ORA-06550: line 29, column 11: PL/SQL: SQL Statement ignored
When you create a table using execute immediate in an anonymous block, use execute immediate to insert the data into it.
DECLARE
ncount NUMBER;
v_sql VARCHAR2(4000);
CURSOR c1
IS
SELECT bank_code,
center_code,
bank_name,
logo
FROM bank
WHERE bank_code ='607143';
BEGIN
SELECT COUNT(1) INTO ncount FROM tab WHERE tname LIKE '%EMP_INFORMATION%';
IF (ncount <= 0) THEN
DBMS_OUTPUT.PUT_LINE (ncount || 'count');
BEGIN
v_sql :=' CREATE TABLE EMP_INFORMATION
(
emp_id VARCHAR2(3),
emp_name VARCHAR2(20),
emp_salary VARCHAR2(3),
emp_department VARCHAR2(3)
)';
EXECUTE IMMEDIATE v_sql;
BEGIN
FOR i IN c1
LOOP
EXECUTE IMMEDIATE 'INSERT
INTO EMP_INFORMATION
(
emp_id,
emp_name,
emp_salary,
emp_department
)
VALUES
(
:a,
:b,
:c,
:d
)' using i.bank_code, i.bank_name, i.center_code, i.logo;
END LOOP;
END;
END;
END IF;
end;
/

PL/SQL: Cursor ::Retrieve a list of employees for each department

How to retrieve list of employees for each department from table EMP into a comma-delimited new table
something like:
[column x:ie deptno] [column y:ie ename]
--------------------------
7 Jesus, María, José
5 Staz, Przemek, Tomek
6 John, Jane, Bob
below table is where I want to put my result from Function concatenate_list compilation
CREATE TABLE Z
(
x NUMBER(2) NOT NULL,
y VARCHAR2 (4000) NOT NULL
);
SET SERVEROUTPUT ON
CREATE OR REPLACE FUNCTION concatenate_list (xy_cursor IN SYS_REFCURSOR)
RETURN VARCHAR2
IS
lret VARCHAR2(30000);
ltemp VARCHAR2(30000);
BEGIN
LOOP
FETCH xy_cursor
INTO ltemp;
EXIT WHEN xy_cursor%notfound;
lret := lret || ',' || ltemp;
END LOOP;
RETURN LTRIM(lret, ',');
END;
/
SHOW ERRORS
how to insert the results from "Function concatenate_lit compile" and get a result as mentioned above.
Maybe using something like this:
INSERT INTO Z( x, y) SELECT e1.x,
concatenate_list(CURSOR(SELECT e2.y FROM EMP e2 WHERE e2.x= e1.x));
but how to set it up form inside the PL/SQL block
This may help you.
declare
type cur_name is ref cursor;
emp_name cur_name;
v_ename emp.ename%type;
v_all_ename varchar2(1000);
v_deptno emp.deptno%type;
cursor c is select deptno,cursor(select ename from emp e where e.deptno=f.deptno) from emp f group by deptno;
begin
open c;
loop
fetch c into v_deptno,emp_name;
exit when c%notfound;
loop
fetch emp_name into v_ename;
exit when emp_name%notfound;
v_all_ename:=v_all_ename||v_ename;
v_all_ename:=v_all_ename||',';
end loop;
dbms_output.put_line(v_deptno||' '||v_all_ename);
v_all_ename:='';
end loop;
close c;
end;

PLSQL, execure formula stored in a table

I'm a newbie in PLSQL. I was just wondering if I can save my formula into a table as string and use it in my functions to calculate some values.
Here is an example:
ID NAME FORMULA
1 test prm_testval*prm_percent/18
2 test2 (prm_testval +20)*prm_percent
what I want to do is to select formula column from the table and use the string in my functions
select t.* from table t where id=1
prm_calculated_value = t.formula
I don't want the string value of formula in here, just the formula itself.
Any ideas, If I can use it or not?
The starting point is execute immediate-statement. It's PL/SQL's eval().
create table formulas (
id number,
name varchar2(20),
formula varchar2(50)
);
insert into formulas values (1, 'test 1', 'prm_testval*prm_percent/18');
insert into formulas values (2, 'test 2', '(prm_testval +20)*prm_percent');
/* eval from: http://www.adp-gmbh.ch/blog/2005/may/5.html */
create or replace function eval (
expr in varchar2
) return varchar2 as
ret varchar2(32767);
begin
execute immediate 'begin :result := ' || expr || '; end;' using out ret;
return ret;
end;
/
create or replace function eval2 (
vars in varchar2,
expr in varchar2
) return varchar2 as
ret varchar2(32767);
begin
execute immediate vars || ' begin :result := ' || expr || '; end;' using out ret;
return ret;
end;
/
create or replace function calc_prm (
id_ in number,
prm_testval in varchar2,
prm_percent in varchar2
) return number as
formula_ formulas.formula%type;
vars constant varchar2(32767) :=
'declare prm_testval constant number := to_number(' || prm_testval ||
'); prm_percent constant number := to_number(' || prm_percent || ');';
begin
select formula into formula_ from formulas where id = id_;
return eval2(vars, formula_);
end;
/
/* call from SQL */
select eval('3*4') from dual;
select calc_prm(1, 97, 10) from dual;
select calc_prm(2, 97, 10) from dual;
/* call from PL/SQL block */
begin
dbms_output.put_line(eval('3*4'));
dbms_output.put_line(calc_prm(1, 97, 10));
dbms_output.put_line(calc_prm(2, 97, 10));
end;
/
Based on this example you can start building your own way to map symbol values (prm_testval and prm_percent) to real values. Next you might want to have a look into DBMS_SQL.
Beware SQL injection when using client supplied data ! See also e.g. Bobby Tables: A guide to preventing SQL injection.

Resources