PL/SQL:用户自定义函数

-------------------用户自定义函数--------------------
函数是可以返回值的命名的 PL/SQL 子程序。 
Oracle的函数是一个独有的对象,它也是由PL/SQL语句编写而成,但的不同的地方是:函数必须返回某些值,而存储过程可以不返回任何值 
创建函数的语法:
  CREATE [OR REPLACE] FUNCTION 
  <function name> [(param1,param2)]
RETURN <datatype>  IS|AS 
  [local declarations]
BEGIN
  Executable Statements;
  RETURN result;
EXCEPTION
  Exception handlers;
END;

定义函数的限制:
函数只能接受 IN 参数,而不能接受 IN OUTOUT 参数
形参不能是 PL/SQL 类型
函数的返回类型也必须是数据库类型
访问函数的两种方式:
使用 PL/SQL 块
使用 SQL 语句

创建函数:
CREATE OR REPLACE FUNCTION fun_hello
  RETURN  VARCHAR2
IS
BEGIN
  RETURN '朋友,您好';
END;SQL 语句调用函数:
SELECT fun_hello FROM DUAL;
1	朋友,您好

CREATE OR REPLACE FUNCTION 
  item_price_range (price NUMBER) 
RETURN VARCHAR2 AS
  min_price NUMBER;
  max_price NUMBER;
BEGIN
  SELECT MAX(ITEMRATE), MIN(ITEMRATE)
  INTO max_price, min_price
  FROM itemfile;
  IF price >= min_price AND price <= max_price 
  THEN
    RETURN '输入的单价介于最低价与最高价之间';
  ELSE
    RETURN '超出范围';
  END IF;
END;

DECLARE
  P NUMBER := 300;
  MSG VARCHAR2(200);
BEGIN
  MSG := item_price_range(300);
  DBMS_OUTPUT.PUT_LINE(MSG);
END;

过 程	                                                   函  数
作为 PL/SQL 语句执行	                                   作为表达式的一部分调用
在规格说明中不包含RETURN 子句	                          必须在规格说明中包含 RETURN 子句
不返回任何值	                                           必须返回单个值
可以包含 RETURN 语句,但是与函数不同,它不能用于返回值	  必须包含至少一条 RETURN 语句

create or replace function fun_hello
  return varchar2--必须在规格说明中包含 RETURN 子句
  is
  begin 
    return '朋友,您好! 今天是'||to_char(sysdate,'DAY');--必须包含至少一条 RETURN 语句
  end;

select fun_hello from dual;
朋友,您好! 今天是TUESDAY  


create or replace function fun_is_first_day
return number
is 
v_result number:=0;
v_day    varchar2(2);
begin 
select to_char(sysdate,'dd')into v_day from dual;
if v_day='01' then
v_result:=1;
else
v_result:=0;
end if;
return(v_result);
end fun_is_first_day;

select fun_is_first_day from dual;

select length('ABCDE') from dual;--5
select length('数据库系统') from dual;--5

create or replace function getstringlen(str in varchar2) return integer is
  result integer;
  i      number;
begin
  result := 0;
  if length(str) = 0 then
    return(result);
  end if;
  for i in 1 .. length(str) loop
    if ascii(substr(str, i, 1)) < 256 then
      result := result + 1;
    else
      result := result + 2;
    end if;
  end loop;
  return(result);
end;

select getstringlen('ABCDE') from dual;--5
select getstringlen('数据库系统') from dual;--10
select getstringlen('ABC数据库cd')from dual;--11

create or replace function find_deptname(emp_no number) return varchar2 as
  dept_no number(2);
  result  dept.dname%type;
begin
  select deptno into dept_no from emp where empno = emp_no;
  select dname into result from dept where deptno = dept_no;
  return result;
exception
  when others then
    return null;
end;

select find_deptname(7369) from dual;
1	RESEARCH

select empno,ename,find_deptname(empno) from emp;
1	7369	SMITH	RESEARCH
2	7499	ALLEN	SALES
3	7521	WARD	SALES
4	7566	JONES	RESEARCH
5	7654	MARTIN	SALES
6	7698	BLAKE	SALES
7	7782	CLARK	RESEARCH
8	7788	SCOTT	RESEARCH
9	7839	KING	ACCOUNTING
10	7844	TURNER	SALES
11	7876	ADAMS	RESEARCH
12	7900	JAMES	SALES
13	7902	FORD	RESEARCH
14	7934	MILLER	ACCOUNTING
15	-10	Not found!	
-------------------用户自定义函数2--------------------
select * from salary;
创建work_day()函数,接受empno雇员编号,并检查所有雇员
的工作天数。标准的天数为22天,雇员每少工作一天从其工资中扣除50元。
函数返回雇员最后的工资,工作天数多于标准天数不加工资,工资扣完为止,
不可以为负值。
create or replace function work_day(emp_num varchar2) return number as
  v_days number;
  v_sal  number;
begin
  --select workdays into v_days from salary where empno = emp_num;--先传入
  --select salary into v_sal from salary where empno = emp_num;
  select workdays,salary into v_days,v_sal from salary  where empno=emp_num;
  v_days := 22 - v_days;--再定义
  if v_days > 0 then
    v_sal := v_sal - 50 * v_days;
  end if;
  if v_sal < 0 then
    v_sal := 0;
  end if;
  return v_sal;--最后输出
end;

select empno,workdays,salary,work_day(empno)as last_salary from salary;

select * from emp;
1	7369	SMITH	CLERK	7902	2018-12-17	2200		20
2	7499	ALLEN	SALESMAN	7698	2018-2-20	2000	1000	30
3	7521	WARD	SALESMAN	7698	2018-2-22	1450	1000	30
4	7566	JONES	MANAGER	7839	2018-4-2	2975		20
5	7654	MARTIN	SALESMAN	7698	2018-9-28	1450	1000	30
6	7698	BLAKE	SALESMAN	7839	2018-5-1	2850	1000	30
7	7782	CLARK	MANAGER	7839	2018-6-9	2450		20
8	7788	SCOTT	ANALYST	7566	1987-4-19	3000		20
9	7839	KING	PRESIDENT		2018-11-17	5000		10
10	7844	TURNER	SALESMAN	7698	2018-9-8	1700	1000	30
11	7876	ADAMS	CLERK	7788	1987-5-23	1300		20
12	7900	JAMES	CLERK	7698	2018-12-3	1150	1000	30
13	7902	FORD	ANALYST	7566	2018-12-3	3000		20
14	7934	MILLER	CLERK	7782	1982-1-23	1500		10
15	-10	Not found!			
			
create or replace function sal_fun(salary number) return varchar2 as
  max_sal number;
  min_sal number;
begin
  select max(sal), min(sal) into max_sal, min_sal from emp;
  if salary <= max_sal and salary >= min_sal then
    return '输入的工资介于最高工资与最低工资之间';
  else
    return '超出范围';
  end if;
end;

declare
  sal number := 1500;
  msg varchar2(200);
begin
  msg := sal_fun(sal);
  dbms_output.put_line(msg);
end;
输出:输入的工资介于最高工资与最低工资之间


 create or replace function cursor_getdata(n integer := 0) return integer is
   n_result integer := 0;
   emp_no   emp.empno%type;
   emp_name emp.ename%type;
   emp_sal  emp.sal%type;
   cursor cur_emp is--声明游标
     select empno, ename, sal from emp;
 begin
   case
     when (n_result = 0) then
       open cur_emp;--打开游标
       loop
         fetch cur_emp--提取行
           into emp_no, emp_name, emp_sal;
         exit when cur_emp%notfound;--提取完退出
         n_result := n_result + 1;
       end loop;
     else
   goto exit0;--跳转
   end case;--结束
   <<exit0>>
   if cur_emp%isopen then--如果游标开启
     close cur_emp;--关闭游标
   end if;
   return n_result;--返回n_result
 end;
--简化1 
  create or replace function cursor_getdata(n integer := 0) return integer is
   n_result integer := 0;
   emp_no   emp.empno%type;
   emp_name emp.ename%type;
   emp_sal  emp.sal%type;
   cursor cur_emp is--声明游标
     select empno, ename, sal from emp;
 begin
   case
     when (n_result = 0) then
       open cur_emp;--打开游标
       loop
         fetch cur_emp--提取行
           into emp_no, emp_name, emp_sal;
         exit when cur_emp%notfound;--提取完退出
         n_result := n_result + 1;
       end loop;
   end case;--结束
   return n_result;--返回n_result
 end;
--简化2 
  create or replace function cursor_getdata(n integer := 0) return integer is
   n_result integer := 0;
   myreco emp%rowtype;--定义一个表示表中一行记录的变量,用来存放要提取的数据
   cursor cur_emp is--声明游标
     select * from emp;
 begin
   case
     when (n_result = 0) then
       open cur_emp;--打开游标
       loop
         fetch cur_emp--提取行(所有字段)
           into myreco;
         exit when cur_emp%notfound;--提取完退出
         n_result := n_result + 1;
       end loop;
   end case;--结束
   return n_result;--返回n_result
 end;
 
 select cursor_getdata from dual;--15

你可能感兴趣的:(数据库应用,sql,oracle,数据库,plsql)