PLSQL 将数据从存储在 varchar2 中的 csv 列表移动到整数集合
PLSQL move data from csv list stored in varchar2 to a collection of integers
甲骨文 Express 11G R2:
在 PLSQL 中,我有一个包含 CSV 值列表的 varchar2,如下所示:
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 秒,加上 "bulk collect into" 大约需要 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;
有比我上面的代码更好的选择吗?
性能会因平台、配置等而异,因此很难给出明确的答案。正则表达式的 0.1s 似乎很多,增加到 6s 来填充一个集合似乎过多。
由于您的字符串仅由数字组成,您可以尝试使用 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 做到这一点。
甲骨文 Express 11G R2: 在 PLSQL 中,我有一个包含 CSV 值列表的 varchar2,如下所示:
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 秒,加上 "bulk collect into" 大约需要 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;
有比我上面的代码更好的选择吗?
性能会因平台、配置等而异,因此很难给出明确的答案。正则表达式的 0.1s 似乎很多,增加到 6s 来填充一个集合似乎过多。
由于您的字符串仅由数字组成,您可以尝试使用 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 做到这一点。