【问题标题】:How to use listagg parameter in Oracle procedure where clause如何在 Oracle 过程 where 子句中使用 listagg 参数
【发布时间】:2021-10-09 16:09:24
【问题描述】:

我使用 LISTAGG 对一系列 ID 进行分组。 这是返回值的示例-

A     1,2,3,4,5    PROC.ABC
B     6,7,8        PROC.ABC
C     2,3,4        PROC.DEF

然后我尝试使用游标并将每个值传递到以下过程:

PROCEDURE abc(id_list IN VARCHAR2) IS
BEGIN
  UPDATE table_a SET flag = 1 WHERE id IN (id_list);
END;

这个错误(“无效号码”错误)因为 id_list 被插入为

'1,2,3,4,5'

,不是

1,2,3,4,5

。我怎样才能让它工作?如果可能,我宁愿不使用动态 SQL。

【问题讨论】:

  • 如果您控制此设计,请不要使用 listagg 和字符串参数 - 而是创建并传递数字集合。
  • SQL 没有处理 CSV 值的本地方法。您必须编写一个,或者切换到支持的东西,例如 JSON、XML 或 Alex 建议的集合。
  • 感谢 Alex 的想法,花了一段时间,但我终于弄明白了

标签: sql oracle stored-procedures


【解决方案1】:

如果您的数据库中安装了 APEX,则可以使用 APEX_STRING.SPLIT 函数将字符串以逗号分隔。如果您知道id_list 始终是数字,您也可以使用APEX_STRING.SPLIT_NUMBERS

PROCEDURE abc (id_list IN VARCHAR2)
IS
BEGIN
    UPDATE table_a
       SET flag = 1
     WHERE id IN (SELECT * FROM TABLE (apex_string.split (id_list, ',')));
END;

【讨论】:

    【解决方案2】:

    首先,您需要创建一个返回值列表的函数。

    FUNCTION TVF_SPLIT (expression CLOB, delimiter CHAR) RETURN sys.ODCIVARCHAR2LIST
    AS
    v_TYPE_TABLE_SEPRATOR sys.ODCIVARCHAR2LIST :=sys.ODCIVARCHAR2LIST();
    v_xml_data CLOB;
    
    BEGIN
    
    v_xml_data := '<r><n>' || replace(expression,delimiter,'</n><n>') || '</n></r>';
    
    SELECT * BULK COLLECT INTO v_TYPE_TABLE_SEPRATOR FROM
        (
            SELECT * FROM
                XMLTABLE ( '/r/*' 
                PASSING xmltype(v_xml_data) 
                COLUMNS 
                    r VARCHAR2(4000) PATH '/n' 
                ) xmlt
        );
    
    RETURN v_TYPE_TABLE_SEPRATOR;
    END;
    
    Select * from table(TVF_SPLIT('1,2,3,4,5',','));
    

    【讨论】:

      【解决方案3】:

      不要使用 listagg;创建一个集合类型。

      create or replace type t_vchar_tab as table of integer
      

      然后在查询中替换listagg-

      CAST(COLLECT(id) AS t_vchar_tab) as id_list
      

      那么程序应该引用带有 MEMBER 的集合

      PROCEDURE abc(id_list t_vchar_tab) IS
      BEGIN
        UPDATE table_a SET flag = 1 WHERE id MEMBER OF id_list;
      END;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-08-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-17
        相关资源
        最近更新 更多