一个带有 CLOB 或 VARCHAR2 输入和 CLOB 或 VARCHAR2 返回值的单个 PLSQL 函数
Posted
技术标签:
【中文标题】一个带有 CLOB 或 VARCHAR2 输入和 CLOB 或 VARCHAR2 返回值的单个 PLSQL 函数【英文标题】:One single PLSQL function with CLOB or VARCHAR2 input and CLOB or VARCHAR2 return value 【发布时间】:2020-12-12 17:59:29 【问题描述】:我需要编写一个 PLSQL 函数,该函数必须同时处理 CLOB 和 VARCHAR2 输入,并分别返回 CLOB 或 VARCHAR2。但是无论输入类型如何,该函数实现的功能都是完全相同的(它执行一系列 REGEXP_REPLACE 调用)。是否可以编写一个可以同时接受 CLOB 和 VARCHAR2 并返回接收到的类型的函数?我想避免编写两个非常相似的函数,从而重复代码。
我的第一个函数是这样的:
FUNCTION Test(i_text CLOB) RETURN CLOB IS
v_text CLOB;
BEGIN
v_text := i_text;
... a series of REGEXP_REPLACE calls like v_text := REGEXP_REPLACE(v_text,...)
RETURN v_text
END;
而我的另一个功能是:
FUNCTION Test(i_text VARCHAR2) RETURN VARCHAR2 IS
v_text VARCHAR2;
BEGIN
v_text := i_text;
... a series of REGEXP_REPLACE calls like v_text := REGEXP_REPLACE(v_text,...)
RETURN v_text
END;
由于函数内部有大量 REGEXP_REPLACE 调用,我宁愿只有一个函数 - 如果可能的话。
CLOB 输入可能很大,因此无法在函数调用之前将 CLOB 转换为 VARCHAR2。
甚至 REGEXP_REPLACE 也适用于各种输入,例如 CHAR、VARCHAR2、NCHAR、NVARCHAR2、CLOB 或 NCLOB。所以这就是为什么我希望有一个解决方案来满足这个需求。
【问题讨论】:
请记住,正则表达式操作在 clob 上会非常缓慢。使用 DBMS_LOB 提供的内置功能可能更有效(取决于您希望如何操作输入字符串)。鉴于您应该考虑两种不同功能的性能优势是否超过维护开销。 【参考方案1】:@BarbarosOzhan 是正确的,您需要一个包来获得重载能力。但是您不需要复制代码。虽然您是正确的,将 CLOB 转换为 VARCHAR2 是不可能的,但没有什么可以阻止您将 VARCHAR2 转换为 CLOB。然后,如果您不扩展正则表达式中的长度,则将结果转换回 VARCHAR2。处理 varchar2 的函数就变成了只处理转换的包装器。
create or replace package test_pkg is
function test(i_text clob) return clob;
function test(i_text varchar2) return varchar2;
end test_pkg;
/
create or replace package body test_pkg is
function test(i_text clob) return clob is
v_text clob;
begin
v_text := i_text;
--...
return v_text;
end test;
function test(i_text varchar2) return varchar2 is
v_text clob;
v_res varchar2(32767); -- 4000 is actually used in SQL statement
begin
v_text := cast(i_text as clob);
v_res := cast (test(v_text) as varchar2);
return v_res;
end test;
end test_pkg;
您的调用例程应该预期并处理异常“ORA-06502: PL/SQL: numeric or value error: string buffer too small”
【讨论】:
谢谢@Belayer。太好了,我不知道从 VARCHAR2 转换为 CLOB 如此简单。这解决了我的问题。 很高兴我能帮上忙。我也不知道——从来没有真正做过。但毕竟 CLOB 基本上是一个很长的 VARCHAR2,这似乎是合乎逻辑的。许多年前,我学到了一种非常有用的技巧,它被称为“有益的一厢情愿”。它来自心理学,但对于开发来说,它基本上翻译为“我希望我能做 X”,所以写一段代码来做 X。如果它有效,那么你可以做到;如果不继续。 我喜欢这样积极的想法:)【参考方案2】:你可以用两个Test
(Overloading in Packages)函数来创建一个包,比如
CREATE OR REPLACE PACKAGE Pkg_Test IS
FUNCTION Test (i_text VARCHAR2) RETURN VARCHAR2
FUNCTION Test (i_text CLOB) RETURN CLOB;
END;
/
CREATE OR REPLACE PACKAGE BODY Pkg_Test IS
FUNCTION Test (i_text VARCHAR2) RETURN VARCHAR2 IS
val VARCHAR2;
BEGIN
SELECT ...
INTO val
FROM tab t
WHERE t.col1 = i_text;
RETURN val;
END;
FUNCTION Test (i_text CLOB) RETURN CLOB IS
val CLOB;
BEGIN
SELECT ....
INTO val
FROM tab t
WHERE t.col2 = i_text;
RETURN val;
END;
END;
/
无论参数的数据类型是什么,都使用与下面相同的名称调用
BEGIN
:result := Pkg_Test.test(:prm);
END;
/
【讨论】:
是的,我知道过程重载,这就是我现在正在做的事情。但即使在这种情况下,我也必须复制一长串(REGEXP_REPLACE 或其他)调用。因为即使在这种情况下,您也有两个独立的函数和两个独立的主体。两者都将在体内具有相同的大量调用。这就是我试图以某种方式避免的。以上是关于一个带有 CLOB 或 VARCHAR2 输入和 CLOB 或 VARCHAR2 返回值的单个 PLSQL 函数的主要内容,如果未能解决你的问题,请参考以下文章