【问题标题】:PLSQL move data from csv list stored in varchar2 to a collection of integersPLSQL 将数据从存储在 varchar2 中的 csv 列表移动到整数集合
【发布时间】:2015-06-17 12:32:49
【问题描述】:

Oracle Express 11G R2: 在 PLSQL 中,我有一个 varchar2,其中包含一个 CSV 值列表,如下所示:

vList:='1212,3232,3232,4343,54545,65654,65665,65654,788787'

我想将这些移动到一个集合中,所以我创建了一个新类型:

CREATE TYPE INTEGER_TT AS TABLE OF INTEGER;

然后声明我的变量:

my_list INTEGER_TT;

用包含 CSV 的 varchar2 中的值填充“my_list”的最快方法是什么(就处理器时间而言,而不是实施时间)?

这是我当前的代码,查询本身运行大约 0.01 秒,添加“批量收集到”大约需要 6 秒,列表大约有 500 个值。

select regexp_substr( vList,'[^,]+', 1, level) intID 
bulk collect into my_list
from dual connect by regexp_substr(vList, '[^,]+', 1, level) is not null;

还有比我上面的代码更好的选择吗?

【问题讨论】:

    标签: sql oracle collections plsql


    【解决方案1】:

    性能会因平台、配置等而有所不同,因此很难给出明确的答案。正则表达式的 0.1 秒似乎很多,而将填充集合增加到 6 秒似乎过多。

    由于您的字符串仅包含数字,您可以尝试使用 XMLTable 的技巧:

    select to_number(column_value)
    bulk collect into my_list
    from xmltable(vList);
    

    这会将您的 CSV 列表传递为 an XQuery expression,并将其解释为 XQuery 序列。但这仅适用于数字,您不能将此方法用于字符串。

    使用随机整数生成的相同 500 元素列表比较方法的示例时序:

    set serveroutput on
    declare
      my_list INTEGER_TT;
      vList varchar2(32767);
      vTime pls_integer;
    begin
      -- create list of 500 random integers
      vTime := dbms_utility.get_time;
      select listagg(trunc(dbms_random.value(1, 10000)), ',')
        within group (order by null)
      into vList
      from dual
      connect by level <= 500;
      dbms_output.put_line('Creating list took ' || (dbms_utility.get_time - vTime));
    
      -- original regex approach
      vTime := dbms_utility.get_time;
      select regexp_substr( vList,'[^,]+', 1, level) intID 
      bulk collect into my_list
      from dual connect by regexp_substr(vList, '[^,]+', 1, level) is not null;
      dbms_output.put_line('Regex took ' || (dbms_utility.get_time - vTime));
    
      -- XMLTable approach
      vTime := dbms_utility.get_time;
      select to_number(column_value)
      bulk collect into my_list
      from xmltable(vList);
      dbms_output.put_line('XMLTable took ' || (dbms_utility.get_time - vTime));
    end;
    /
    

    获取以下时间,以百分之一秒为单位:

    Creating list took 2
    Regex took 188
    XMLTable took 3
    

    你可能会因为不同的结果,或者不同幅度的差异......


    如果您这样做是为了将集合用作 SQL 查询中的数据源(这是可能的,因为它是架构级别的集合类型),您可以跳过该步骤。如果您使用的是table(my_list),则可以直接参考xmltable(vList)。您可以完全避免使用 PL/SQL,具体取决于您正在做什么;虽然你本来可以用 CTE 做到这一点。

    【讨论】:

    • 很好的解决方案,我的查询结果:创建列表需要 89 正则表达式需要 1062 XMLTable 需要 6
    • 嗨@Alex,请注意,vList 的最大大小似乎是 4000,超过这个数量,“来自 xmltable(vList) 会给出错误:“ORA-01460:未实现或不合理请求转换”我看不到任何解决方法。
    • @ASims - 这是在 SQL 上下文中使用 XMLTable,其中字符串大小限制为 4000(无论如何直到 12c)。您需要将 vList 设为 CLOB 才能超过该长度。 (验证了一个包含 1000 个数字的 CLOB,长度为 4874)。
    猜你喜欢
    • 2013-11-09
    • 2017-04-06
    • 2018-09-23
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    • 2015-12-17
    • 1970-01-01
    • 2020-07-01
    相关资源
    最近更新 更多