如何通过使用带有 PLSQL 的触发器来修改包含特定值的 CLOB 行?

Posted

技术标签:

【中文标题】如何通过使用带有 PLSQL 的触发器来修改包含特定值的 CLOB 行?【英文标题】:How to modify a CLOB line containing a certain value by using a trigger with PLSQL? 【发布时间】:2020-04-09 16:07:46 【问题描述】:

我正在努力解决有关 CLOB 的问题。 我想创建一个触发器(更新后),它更新一个表的列,它是一个 CLOB。 此 CLOB 包含以下形式的行:

foo|132|65|12/08/2016|18395|
bar|132|54|15/08/2014|32434343|

我想修改 CLOB,使以“foo”开头的行的值是“18395”除以 1000。该行看起来像

foo|132|65|12/08/2016|18.395|

有没有快速修改我的 CLOB 的方法?

感谢您的帮助。

编辑:我找到了一种修改 CLOB 行的方法,我需要做的只是修改 CLOB 来替换

foo|132|65|12/08/2016|18395|

通过

foo|132|65|12/08/2016|18.395|

【问题讨论】:

是触发器所针对的表中的 CLOB - 如果是,为什么在更新后;如果不是,它们有什么关系?您如何决定修改该值 - 仅当 CLOB 本身已更改,或者任何其他列也发生更改时,这可能导致该元素被多次划分?您如何确定要更新 CLOB 中的哪一行(即为什么是“foo”)?它总是该行的第 5 个元素吗? (为什么要将分隔数据行存储为字符串而不是单个关系值?) 是的,CLOB 在触发器中。此 CLOB 来自我可以从 SFTP 连接获得的响应文件。在获取响应文件之前,CLOB 单元格是空的,这就是我想使用更新后触发器来修改 CLOB 的原因。 “foo”只是一个例子,我将用另一个字符串替换它。我需要修改与此行关联的值,因为它是一种特殊情况(我从服务器收到的值是实际值的倍数)。我不明白最后一个问题。 请编辑您的问题以解释整个场景,包括表结构、起始数据、触发操作是什么以及如何获得您想要的最终结果。请参阅How do I ask a good question?,尤其是关于minimal reproducible example 的部分。 不存储分隔值。这真是个坏主意。如果您必须在一列中存储多个值(并破坏规范化),则使用 JSON 可能是更好的解决方案,因为有许多函数可用于访问单个元素。 【参考方案1】:

这是相当长但有效的。 首先创建一个类型:

create or replace TYPE  "array_str" AS VARRAY(10) OF VARCHAR(256);

然后创建一个函数,该函数将返回基于分隔符的数组:

FUNCTION string_to_array (
    string_delimited   IN   VARCHAR2,
    delimiter          IN   VARCHAR2 DEFAULT ','
) RETURN array_str IS
    pls_idx        PLS_INTEGER;
    split_string   array_str := array_str();
    pls_del_len    PLS_INTEGER := length(delimiter);
BEGIN
    IF string_delimited IS NOT NULL THEN
        LOOP
    -- search for delimiter string
            pls_idx := instr(l_string_delimited, delimiter);
    -- increase the size of array
            split_string.extend;

    -- check last search of delimiter is success
            IF pls_idx = 0 THEN
                split_string(l_split_string.count) := substr(l_string_delimited, 1);
            ELSE
                split_string(l_split_string.count) := substr(l_string_delimited, 1, pls_idx - 1);
            END IF;

    -- exit from loop when last string

            EXIT WHEN nvl(l_pls_idx, 0) = 0;
            string_delimited := substr(l_string_delimited, pls_idx + pls_del_len);
        END LOOP;
    END IF;

    RETURN split_string;
END string_to_array;

然后创建您的触发器:

CREATE OR REPLACE TRIGGER your_trigger AFTER
    UPDATE ON table_name
    FOR EACH ROW
DECLARE
    clob_array   array_str;
    clob_str     CLOB := '';
BEGIN
    clob_array := string_to_array(:new.new_clob, '|');
    IF ( clob_array(1) = 'foo' ) THEN
        clob_array(5) := to_number(clob_array(5) / 1000);
    END IF;

    FOR i IN 1..clob_array.count - 1 LOOP clob_str := clob_str
                                                      || to_char(clob_array(i))
                                                      || '|';
    END LOOP;

    -- do something with clob_str

END;

【讨论】:

上述只有 1 个问题,但是一个致命的问题。 AFTER 触发器无法更改值。如果要更改数据,必须使用 BEFORE 触发器。 @Belayer 问题是我的CLOB在更新前是空的,因为它来自响应文件。 您误解了之前和之后的含义。两者都是 UPDATE 语句的一个阶段。您可以这样看 在执行之前,直到设置最终值,您可以有多个之前触发器,每个触发器都可以修改数据值。在数据值固定且无法再更改之前,触发器不会运行。直到所有触发器都完成后,UPDATE 语句才完成。

以上是关于如何通过使用带有 PLSQL 的触发器来修改包含特定值的 CLOB 行?的主要内容,如果未能解决你的问题,请参考以下文章

在Oracle中,我一直收到PLSQL的Fatal ErrorReset连接。

如何检查时间是不是大于或小于PLSQL中的另一个时间

if语句触发之前的plsql完整循环?

plsql - 带有集合的 Oracle 选择

任务调度开源框架Quartz动态添加修改和删除定时任务

带有数据字典中过程的PLSQL包[重复]