0

我有一张桌子: Table_1 如下所示:

id   |   column1
-----------------
10   |   abc, kdm
20   |   xyz, lop, nkk

我想要的是转换表如下所示:

id   |   column1
-----------------
10   |   abc
10   |   kdm
20   |   xyz 
20   |   lop
20   |   nkk

为此,我使用了这样的查询:

select id, regexp_substr(column1,'[^,]+', 1, level) from Table_1 
connect by regexp_substr(column1, '[^,]+', 1, level) is not null;

只要逗号分隔值的数量较少,此查询就可以正常工作。但是当它长大时,它会消耗越来越多的时间来处理。

我想到的一种解决方案是创建一个单独的表,然后通过迭代 Table_1 的值来插入值。

伪代码如下:

FOR r in each row
    FOR i in 1..length(comma_separated_values)
       insert into new_table values(id, select regexp_substr(column1,'[^,]+', 1, i) from Table_1 
    End LOOP;
End LOOP;

但是由于随着逗号分隔值的增长,这也会消耗很多时间,是否有任何其他最佳方法可以做到这一点(最好不要使用另一个表,但临时/虚拟表可以)?

我正在使用 Oracle SQL。

提前致谢。

4

3 回答 3

1

无法承受规范化问题,您的原始查询实际上不起作用。在测试数据上运行时:

SQL> with Table_1(id, column1) as (
  2    select 10, 'abc, kdm' from dual
  3    union
  4    select 20, 'xyz, lop, nkk' from dual
  5  )
  6  select id, regexp_substr(column1,'[^,]+', 1, level) from Table_1
  7  connect by regexp_substr(column1, '[^,]+', 1, level) is not null;

        ID REGEXP_SUBSTR
---------- -------------
        10 abc
        10  kdm
        20  nkk
        20  lop
        20  nkk
        20 xyz
        10  kdm
        20  nkk
        20  lop
        20  nkk

10 rows selected.

SQL>

因此,当您添加更多值时,问题会呈指数级增长,因此您的性能会下降。通过添加第三行进行测试。此外,您的分隔符是逗号空格,而不仅仅是逗号。 并且用于解析列表的正则表达式形式('[^,]+')不适用于空值,应避免使用。不幸的是,这是您将看到的最常见的正则表达式,作为解析列表的答案。

试试这个,它应该可以轻松处理更大的列表:

SQL> with Table_1(id, column1) as (
     select 10, 'abc, kdm' from dual
     union
     select 20, 'xyz, lop, nkk' from dual
   )
   SELECT id, -- column1,
              --  COLUMN_VALUE AS match_nbr,
          REGEXP_SUBSTR( column1 ,'(.*?)(, |$)', 1, COLUMN_VALUE, NULL, 1 ) AS match_value
   FROM
     Table_1,
     TABLE(
       CAST(
         MULTISET(
           SELECT LEVEL
           FROM   DUAL
           CONNECT BY LEVEL <= REGEXP_COUNT(column1 , ',' )+1
         ) AS SYS.ODCINUMBERLIST
       )
     );

        ID MATCH_VALUE
---------- -------------
        10 abc
        10 kdm
        20 xyz
        20 lop
        20 nkk

SQL>

基本上,这会创建一个表,每行一行,列表中的元素数量(包含元素编号)并将其与主表连接起来。
取消注释 COLUMN_VALUE 值行以查看元素的编号。它假定数据不包含逗号。

于 2015-08-31T20:04:31.357 回答
1

显然,兰迪提出的解决根本问题的建议是理想的。如果这是不可能的,那么有多种选择可供选择。许多都在这里列出 。一般来说,虽然可以提高性能的简单解决方案是在 column1 中找到最大数量的值,创建一个包含那么多列的临时表,然后将该临时表转换为您想要的格式。即,有一个中间步骤,表格看起来像id|val1|val2|val3|..|valn

于 2015-08-31T19:31:22.667 回答
0

您可以为此尝试 DBMS_UTILITY.COMMA_TO_TABLE 程序,我想用户定义的解决方案应该更快。

文档链接: http: //docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_util.htm

于 2015-08-31T19:20:11.527 回答