oracle 自定义函数传参可以判断值么
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了oracle 自定义函数传参可以判断值么相关的知识,希望对你有一定的参考价值。
在传递0和空的时候返回当天,就不输入0和引号,直接用括号表示,
比如这样:weekday()代表当天,weekday(-1)代表昨天,我的代码如下:
CREATE OR REPLACE FUNCTION SCUPUSER.WEEKDAY(DD number)
RETURN varchar2
IS
BEGIN
IF DD IS NOT NULL
THEN
RETURN TO_CHAR (SYSDATE + DD, 'DAY', 'NLS_DATE_LANGUAGE=AMERICAN');
ELSE
IF (DD = 0 OR DD IS NULL)
THEN
RETURN TO_CHAR (SYSDATE, 'DAY', 'NLS_DATE_LANGUAGE=AMERICAN');
END IF;
END IF;
END;
-- 19-1:建立无参数的函数
CREATE OR REPLACE FUNCTION cur_datetime
RETURN VARCHAR2
IS
BEGIN
RETURN TO_CHAR(sysdate,
'YYYY"年"MM"月"DD"日"HH24″时"MI"分"SS"秒"');
END;
/
-- 19-2:建立带有输入参数的函数
CREATE OR REPLACE FUNCTION get_sal(name VARCHAR2)
RETURN NUMBER
AS
v_sal emp.sal%TYPE;
BEGIN
SELECT sal INTO v_sal FROM emp WHERE upper(ename)=upper(name);
RETURN v_sal;
END;
/
-- 19-3:建立带有输出参数的函数
CREATE OR REPLACE FUNCTION get_info
(eno NUMBER,title OUT VARCHAR2) RETURN VARCHAR2
AS
name emp.ename%TYPE;
BEGIN
SELECT ename,job INTO name,title FROM emp
WHERE empno=eno;
RETURN name;
END;
/
-- 19-4:建立带有输入输出参数的函数
CREATE OR REPLACE FUNCTION get_upd_info
(eno NUMBER,sal_chg IN OUT NUMBER) RETURN VARCHAR2
AS
name emp.ename%TYPE;
BEGIN
UPDATE emp SET sal=sal+sal_chg WHERE empno=eno
RETURNING ename,sal INTO name,sal_chg;
RETURN name;
END;
/
-- 19-5:建立结果缓存函数
CREATE OR REPLACE FUNCTION get_name(no VARCHAR2)
RETURN NUMBER RESULT_CACHE RELIES_ON(emp)
AS
v_name emp.ename%TYPE;
BEGIN
SELECT ename INTO v_name FROM emp WHERE empno=no;
RETURN v_name;
END;
/
-- 19-6:调用无参数的函数
BEGIN
dbms_output.put_line(cur_datetime);
END;
/
-- 19-7:调用带有输入参数的函数
BEGIN
dbms_output.put_line('工资:'||get_sal('&name'));
END;
/
-- 19-8:调用带有输出参数的函数
DECLARE
v_name emp.ename%TYPE;
v_job emp.job%TYPE;
BEGIN
v_name:=get_info(&eno,v_job);
dbms_output.put_line('姓名:'||v_name||',岗位:'||v_job);
END;
/
-- 19-9:调用带有输入输出参数的函数
DECLARE
v_empno emp.empno%TYPE;
v_name emp.ename%TYPE;
v_salchg emp.sal%TYPE;
BEGIN
v_empno:=&eno;
v_salchg:=&incre;
v_name:=get_upd_info(v_empno,v_salchg);
dbms_output.put_line('姓名:'||v_name||',新工资:'||v_salchg);
END;
/
-- 19-10:使用位置传递为参数传递变量和数据
SELECT get_sal('&name') 工资 FROM dual;
-- 19-11:使用名称传递为参数传递变量和数据
VAR salary NUMBER
EXEC :salary:=get_sal(name=>'&name')
-- 19-12:使用组合传递为参数传递变量和数据
VAR name VARCHAR2(10)
VAR sal_chg NUMBER
EXEC :sal_chg:=200
EXEC :name:=get_upd_info(&eno,:sal_chg)
PRINT name sal_chg
-- 19-13:在sql语句中调用pl/sql函数
SELECT get_sal(name=>'scott') salary FROM dual;
-- 19-14:使用异常处理
CREATE OR REPLACE FUNCTION get_sal(name VARCHAR2)
RETURN NUMBER
AS
v_sal emp.sal%TYPE;
BEGIN
SELECT sal INTO v_sal FROM emp
WHERE upper(ename)=upper(name);
RETURN v_sal;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20000,'该雇员不存在');
END;
/
-- 19-15:使用纪录类型作为返回类型
CREATE OR REPLACE FUNCTION get_info
(eno NUMBER) RETURN emp%ROWTYPE
IS
emp_record emp%ROWTYPE;
BEGIN
SELECT * INTO emp_record FROM emp WHERE empno=eno;
RETURN emp_record;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20000,'该雇员不存在');
END;
/
DECLARE
emp_record emp%ROWTYPE;
BEGIN
emp_record:=get_info(&eno);
dbms_output.put_line('姓名:'||emp_record.ename||',部门号:'||emp_record.deptno);
END;
/
-- 19-16:使用集合类型作为返回类型
CREATE OR REPLACE TYPE ename_table_type IS TABLE OF VARCHAR2(10);
/
CREATE OR REPLACE FUNCTION get_name
(dno NUMBER) RETURN ename_table_type IS
ename_table ename_table_type;
BEGIN
SELECT ename BULK COLLECT INTO ename_table FROM emp WHERE deptno=dno;
RETURN ename_table;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20099,'该部门不存在');
END;
/
DECLARE
ename_table ename_table_type;
BEGIN
ename_table:=get_name(&dno);
FOR i IN 1..ename_table.COUNT LOOP
dbms_output.put_line('姓名:'||ename_table(i));
END LOOP;
END;
/
-- 19-17:删除函数
DROP FUNCTION get_name;
-- 19-18:显示编译错误
SHOW ERRORS
-- 19-19:确定函数状态
SELECT object_name FROM user_objects WHERE status='INVALID' AND object_type='FUNCTION';
-- 19-20:编译函数
ALTER FUNCTION get_info COMPILE;
-- 19-21:查看函数代码
SELECT text FROM user_source WHERE name='GET_INFO'; 参考技术B 感觉你的if else 逻辑有点乱,编译会报错的追问
没有啊,怎么会混乱,编译成功了的,并且可以执行
好吧,这可能是我编程习惯的问题。。。
Oracle 函数并发
【中文标题】Oracle 函数并发【英文标题】:Oracle function concurrency 【发布时间】:2010-09-27 01:44:12 【问题描述】:我目前有一个 INSERT TRIGGER,它在 Oracle 10g 中运行一个自定义函数,该函数生成一个时髦的字母数字代码,用作插入的一部分。
我确实需要确保函数(甚至触发器)是线程安全的,这样如果两个用户同时激活触发器,触发器中使用的函数不会为两个用户返回相同的代码。
触发器中的流程如下:
开始
-
根据业务逻辑判断是否需要继续
运行自定义函数获取新代码
使用返回的代码作为插入到不同的表中
结束
主要问题是,如果在第 2 步运行时,一个单独的线程触发触发器,该触发器也进入第 2 步,并返回与第一个线程相同的代码。 (我知道这是一个非常紧张的情况,但我们需要处理它)。
我想到了两种主要的方法:
目前我想到的目前最好的方法是在触发器一开始就将触发器中使用的表锁定为“独占模式”,并且不要指定NOWAIT属性的锁。这样,触发器的每个后续激活都会有点“停止并等待”锁可用,因此等待其他线程完成触发器。
我很想锁定表任何拒绝读取表,但我似乎可以找到如何在 Oracle 中执行此操作。
我的想法并不理想,但应该可行,但是我很想听听任何可能对此有更好想法的人的意见!
非常感谢您提供的任何帮助。
干杯, 标记
【问题讨论】:
在第 2 步中,您是否选择或更新任何表?它用什么来驱动返回的代码? Sysdate,或者一些表值,或者外部 C 函数或者什么? 【参考方案1】:这里无需计算排他性。 Oracle 通过管理您的事务来做到这一点。
关键是你的“自定义函数”的每次调用都需要返回一个唯一的代码。
这意味着不使用系统日期/时间,而是使用其他东西来确保唯一性。
我推荐这个:
select sys_guid() from dual;
使用sys_guid()
加盐你的功能,一切都应该在触发领域。
请不要尝试使用此值更新其他表,否则您将需要处理变异表等。
编辑:显然,正如其他几个人提到的那样,在触发器中使用序列来播种您的函数是另一个很好的建议,因为 Oracle 强制执行唯一性。虽然将其用作种子可能会产生可预测的结果,所以如果“自定义函数”是密码重置或类似的东西,请小心。
【讨论】:
好答案。唯一值的另一种选择是简单序列,无论事务、回滚等如何,它都不会两次返回相同的值。 一个序列会很棒,但是,我需要在我的函数中生成一个业务特定的字母数字代码......你能把它作为某种自定义序列吗? @BQ,你所说的“加盐”是什么意思?你能详细说明一下吗?谢谢。 如果您描述您的“业务特定字母数字代码”,我们可能不需要猜测太多。 :) 您根本不需要知道它是什么,它只是函数生成的代码,问题是,您能否创建一个使用该函数而不是标准数字增量的自定义序列【参考方案2】:“你根本不需要知道它是什么,它只是函数生成的代码” 那时它必须基于时间,因为其他任何事情我们都需要知道才能给出适当的答案。不确定是否影响您的吞吐量。 您可以将 DBMS_LOCK.REQUEST 视为 1a,将 DBMS_LOCK.SLEEP 视为 2a,将 DBMS_LOCK.RELEASE 视为 2b。这可以确保每个锁都保持一秒钟,以便在任何一秒钟内只能发生一次插入。
如果它是基于序列的,Oracle 确保您不会两次获得相同的序列
如果它取决于会话/包状态(例如在会话中递增),那么会话一次只能发生一个插入(尽管它可能是多行插入...选择甚至是多行插入)表插入)。
如果它依赖于数据库状态(即函数执行查询),您需要考虑事务,而不是语句。您仍然可以使用 DBMS_LOCK,但您需要在提交后手动释放锁,以确保等待会话确实等到新数据提交并可见。
【讨论】:
【参考方案3】:一种解决方案是使用 Oracle 序列向生成唯一字符串的自定义代码提供数据。 Oracle 正是出于这个原因提供了序列——因此生成唯一 ID 的方法是线程安全的。查看 here 获取 Oracle 9i(我使用的版本)的文档。
【讨论】:
以上是关于oracle 自定义函数传参可以判断值么的主要内容,如果未能解决你的问题,请参考以下文章