You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Oracle PLSQL和SQL中实现带命名占位符的字符串插值功能

Oracle PLSQL 字符串插值包实现

以下实现完全符合需求约定,同时支持PL/SQL关联数组传参、SQL侧CSV键值对传参,内置双大括号转义处理,做了基础性能优化适配低频调用场景。

包规范(pkg_interpolation.pks)

CREATE OR REPLACE PACKAGE pkg_interpolation IS
    -- 定义关联数组字典类型,供PLSQL侧调用传参
    TYPE ty_dictionary IS TABLE OF NVARCHAR2(1000) INDEX BY VARCHAR2(200);

    -- PLSQL调用入口:传入模板和关联数组参数
    FUNCTION fn_format(p_template IN NVARCHAR2, p_vars IN ty_dictionary) RETURN NVARCHAR2;

    -- SQL调用入口:传入模板和CSV格式键值对(格式:键1,值1,键2,值2...)
    FUNCTION fn_format(p_template IN NVARCHAR2, p_csv_kv IN VARCHAR2) RETURN NVARCHAR2;
END pkg_interpolation;
/

包体(pkg_interpolation.pkb)

CREATE OR REPLACE PACKAGE BODY pkg_interpolation IS
    -- 临时转义标记,需确保不会出现在业务模板/参数中
    C_ESC_OPEN CONSTANT VARCHAR2(20) := '§_ESC_OPEN_§';
    C_ESC_CLOSE CONSTANT VARCHAR2(20) := '§_ESC_CLOSE_§';

    FUNCTION fn_format(p_template IN NVARCHAR2, p_vars IN ty_dictionary) RETURN NVARCHAR2 IS
        v_result NVARCHAR2(32767);
        v_key VARCHAR2(200);
    BEGIN
        -- 第一步:先转义双大括号,避免被识别为占位符
        v_result := REPLACE(REPLACE(p_template, '{{', C_ESC_OPEN), '}}', C_ESC_CLOSE);

        -- 第二步:遍历所有参数替换占位符
        v_key := p_vars.FIRST;
        WHILE v_key IS NOT NULL LOOP
            v_result := REPLACE(v_result, '{' || v_key || '}', p_vars(v_key));
            v_key := p_vars.NEXT(v_key);
        END LOOP;

        -- 第三步:还原转义的大括号
        v_result := REPLACE(REPLACE(v_result, C_ESC_OPEN, '{'), C_ESC_CLOSE, '}');

        RETURN v_result;
    END fn_format;

    FUNCTION fn_format(p_template IN NVARCHAR2, p_csv_kv IN VARCHAR2) RETURN NVARCHAR2 IS
        v_vars ty_dictionary;
        v_kv_list DBMS_UTILITY.UNCL_ARRAY;
        v_kv_count BINARY_INTEGER;
    BEGIN
        -- 拆分CSV键值对
        DBMS_UTILITY.COMMA_TO_TABLE(
            list => TRIM(BOTH ',' FROM p_csv_kv),
            tablen => v_kv_count,
            tab => v_kv_list
        );

        -- 按顺序读取键、值存入字典
        FOR i IN 1..v_kv_count STEP 2 LOOP
            IF i+1 <= v_kv_count THEN
                v_vars(TRIM(v_kv_list(i))) := TRIM(v_kv_list(i+1));
            END IF;
        END LOOP;

        -- 调用重载方法执行替换
        RETURN fn_format(p_template, v_vars);
    END fn_format;
END pkg_interpolation;
/

调用示例

PLSQL 侧调用

DECLARE 
    v_template NVARCHAR2(500);
    v_name NVARCHAR2(50) := 'Jane';
    v_age NVARCHAR2(50) := '26';
    v_output NVARCHAR2(1000); 
    v_vars pkg_interpolation.ty_dictionary;
BEGIN
    v_template := 'Hi my name is {name}, I am aged {age}, yes {age}! Replaced placeholders {{name}}, {{age}}';
    v_vars('name') := v_name;
    v_vars('age') := v_age;

    v_output:= pkg_interpolation.fn_format(v_template, v_vars);
    -- 输出:Hi my name is Jane, I am aged 26, yes 26! Replaced placeholders {name}, {age}
    dbms_output.put_line('output: ' || v_output);
END;
/

SQL 侧调用(CSV传参)

SELECT pkg_interpolation.fn_format(
    'Hi my name is {name}, I am aged {age}, yes {age}! Replaced placeholders {{name}}, {{age}}',
    'name, Jane, age, 26'
) AS interpolated_result 
FROM dual;

执行后返回结果与预期完全一致。

性能优化说明

  • 仅做3轮全字符串替换(转义、参数替换、转义还原),避免逐字符扫描模板
  • 重复占位符无需重复匹配,REPLACE函数一次性替换所有同名字段
  • 无递归正则、嵌套循环等高开销逻辑,即使长模板执行效率也可控
  • 采用Oracle内置的DBMS_UTILITY.COMMA_TO_TABLE拆分CSV,比自定义正则拆分效率更高

内容的提问来源于stack exchange,提问作者Rax

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 05:18:04