SQL 使用正则表达式插入
SQL insert with regexp
我有一个 table 数据格式如下
col1 col2
a1 a2;a3;a4
b1 b2
c1 c2;c3
d1 null
...
我正在尝试拆分字符串,获取 col1/col2 的唯一组合并将它们插入 tableB。所以预期的结果应该是这样的:
a1 a2
a1 a3
a1 a4
b1 b2
c1 c2
c1 c3
...
我尝试了以下查询:
INSERT INTO tableB (col1, col2)
SELECT col1, (regexp_substr(col2,'[^;]+', 1, LEVEL)) FROM tableA
CONNECT BY regexp_substr(col2, '[^;]+', 1, LEVEL) IS NOT NULL;
不确定这里出了什么问题,但它一直在执行(实际上持续了一个多小时),当我最终取消任务时,没有插入任何内容。 table 相当大(大约 25000 行),但我用更大的 table 做了类似的插入并且它们工作正常。
我还尝试添加一个 where 子句(虽然它看起来多余)
WHERE col2 LIKE'%;%'
这也无济于事。
任何建议都会很棒。
编辑:我尝试计算 col2 中子字符串的最大数量,以估计要插入的行数,发现最大值为 42 个子字符串。整个 table 有 25814 行,所以最坏的情况是插入 1084104 行。如果这与它有关。
您可以尝试的一件事是 select 所有 distinct
值。
INSERT INTO tableB (col1, col2)
SELECT distinct col1, (regexp_substr(col2,'[^;]+', 1, LEVEL))
FROM tableA
CONNECT BY regexp_substr(col2, '[^;]+', 1, LEVEL) IS NOT NULL;
commit;
如果您需要永久更改,您还应该 commit
交易。
虽然我仍然不太明白初始查询有什么问题,但我找到了解决方法。包含我要拆分的字符串的列是 participantcountries
,p_id
包含唯一标识符。
CREATE OR REPLACE PROCEDURE split_countries IS
CURSOR get_rows IS
SELECT p_id, participantcountries
FROM staging_projects;
row_rec get_rows%ROWTYPE;
nb_countries number:=0;
country VARCHAR2(4);
BEGIN
OPEN get_rows;
LOOP
FETCH get_rows INTO row_rec;
EXIT WHEN get_rows%NOTFOUND;
SELECT regexp_count(row_rec.participantcountries, ';') INTO nb_countries
FROM staging_projects
WHERE p_id=row_rec.p_id;
IF (row_rec.participantcountries IS NULL) THEN
nb_countries:=0; -- if the field is null set counter to zero
ELSE
nb_countries:=nb_countries+1; -- nb of delimiters so +1 --> number of items
END IF;
WHILE (nb_countries >0) LOOP -- loop and get single country at current counter position
SELECT (regexp_substr(PARTICIPANTCOUNTRIES,'[^;]+', 1, nb_countries)) INTO country
FROM (SELECT * FROM staging_projects WHERE p_id=row_rec.p_id)
WHERE participantcountries IS NOT NULL;
nb_countries:=nb_countries-1;
INSERT INTO project_countries(proj_id, country_code) VALUES(row_rec.p_id, country);
END LOOP;
END LOOP;
CLOSE get_rows;
END split_countries;
这很好用,但对于手头的问题来说,这似乎是一个过于复杂的解决方案。
不要使用连接方式将字符串拆分成行。
使用执行 varchar2 -> 集合拆分的 PL/SQL 过程。
对于临时查询,坚持使用 xmltable
作为将字符串拆分为行的简单方法(它比 PL/SQL 慢一点)。
以下类型的查询预计每次输入 1000 行需要 3-4 秒。
select t.col1, c2.val
from (
select 'a1' col1, 'a2;a3;a4' col2 from dual union all
select 'b1', 'b2' from dual union all
select 'c1', 'c2;c3' from dual union all
select 'd1', null from dual
) t
, xmltable('$WTF' passing
xmlquery(('"'||replace(replace(t.col2,'"','""'),';','","')||'"')
returning sequence
) as wtf
columns val varchar2(4000) path '.'
)(+) c2
我有一个 table 数据格式如下
col1 col2
a1 a2;a3;a4
b1 b2
c1 c2;c3
d1 null
...
我正在尝试拆分字符串,获取 col1/col2 的唯一组合并将它们插入 tableB。所以预期的结果应该是这样的:
a1 a2
a1 a3
a1 a4
b1 b2
c1 c2
c1 c3
...
我尝试了以下查询:
INSERT INTO tableB (col1, col2)
SELECT col1, (regexp_substr(col2,'[^;]+', 1, LEVEL)) FROM tableA
CONNECT BY regexp_substr(col2, '[^;]+', 1, LEVEL) IS NOT NULL;
不确定这里出了什么问题,但它一直在执行(实际上持续了一个多小时),当我最终取消任务时,没有插入任何内容。 table 相当大(大约 25000 行),但我用更大的 table 做了类似的插入并且它们工作正常。
我还尝试添加一个 where 子句(虽然它看起来多余)
WHERE col2 LIKE'%;%'
这也无济于事。 任何建议都会很棒。
编辑:我尝试计算 col2 中子字符串的最大数量,以估计要插入的行数,发现最大值为 42 个子字符串。整个 table 有 25814 行,所以最坏的情况是插入 1084104 行。如果这与它有关。
您可以尝试的一件事是 select 所有 distinct
值。
INSERT INTO tableB (col1, col2)
SELECT distinct col1, (regexp_substr(col2,'[^;]+', 1, LEVEL))
FROM tableA
CONNECT BY regexp_substr(col2, '[^;]+', 1, LEVEL) IS NOT NULL;
commit;
如果您需要永久更改,您还应该 commit
交易。
虽然我仍然不太明白初始查询有什么问题,但我找到了解决方法。包含我要拆分的字符串的列是 participantcountries
,p_id
包含唯一标识符。
CREATE OR REPLACE PROCEDURE split_countries IS
CURSOR get_rows IS
SELECT p_id, participantcountries
FROM staging_projects;
row_rec get_rows%ROWTYPE;
nb_countries number:=0;
country VARCHAR2(4);
BEGIN
OPEN get_rows;
LOOP
FETCH get_rows INTO row_rec;
EXIT WHEN get_rows%NOTFOUND;
SELECT regexp_count(row_rec.participantcountries, ';') INTO nb_countries
FROM staging_projects
WHERE p_id=row_rec.p_id;
IF (row_rec.participantcountries IS NULL) THEN
nb_countries:=0; -- if the field is null set counter to zero
ELSE
nb_countries:=nb_countries+1; -- nb of delimiters so +1 --> number of items
END IF;
WHILE (nb_countries >0) LOOP -- loop and get single country at current counter position
SELECT (regexp_substr(PARTICIPANTCOUNTRIES,'[^;]+', 1, nb_countries)) INTO country
FROM (SELECT * FROM staging_projects WHERE p_id=row_rec.p_id)
WHERE participantcountries IS NOT NULL;
nb_countries:=nb_countries-1;
INSERT INTO project_countries(proj_id, country_code) VALUES(row_rec.p_id, country);
END LOOP;
END LOOP;
CLOSE get_rows;
END split_countries;
这很好用,但对于手头的问题来说,这似乎是一个过于复杂的解决方案。
不要使用连接方式将字符串拆分成行。
使用执行 varchar2 -> 集合拆分的 PL/SQL 过程。
对于临时查询,坚持使用 xmltable
作为将字符串拆分为行的简单方法(它比 PL/SQL 慢一点)。
以下类型的查询预计每次输入 1000 行需要 3-4 秒。
select t.col1, c2.val
from (
select 'a1' col1, 'a2;a3;a4' col2 from dual union all
select 'b1', 'b2' from dual union all
select 'c1', 'c2;c3' from dual union all
select 'd1', null from dual
) t
, xmltable('$WTF' passing
xmlquery(('"'||replace(replace(t.col2,'"','""'),';','","')||'"')
returning sequence
) as wtf
columns val varchar2(4000) path '.'
)(+) c2