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 交易。

虽然我仍然不太明白初始查询有什么问题,但我找到了解决方法。包含我要拆分的字符串的列是 participantcountriesp_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

Fiddle: http://sqlfiddle.com/#!4/9eecb7d/5059