一个带有 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 函数的主要内容,如果未能解决你的问题,请参考以下文章

oracle中怎样修改varchar2字段为clob字段

oracle中clob可以转成varchar2吗

CLOB vs. VARCHAR2 还有其他选择吗?

oracle修改字段类型由varchar2修改为clob类型

Oracle中表列由VARCHAR2类型改成CLOB

Oracle:将 VARCHAR2 列更改为 CLOB