【问题标题】:Comma Separated values in OracleOracle中的逗号分隔值
【发布时间】:2011-06-09 03:29:04
【问题描述】:

我有一列用逗号分隔值,例如6,7,99.3334

我需要编写一个 PL SQL 过程来分别给我这些值。列的长度为 40。

谁能帮我解决这个问题?

【问题讨论】:

标签: oracle plsql


【解决方案1】:

可能是这样的吗?

with my as (
  select '6,7,99.3334' str
    from dual
)
select 
  regexp_substr(my.str,'[^,]+',1,level) part
from my
connect by level <= length(regexp_replace(my.str,'[^,]+')) + 1
;

【讨论】:

    【解决方案2】:

    对于非正则表达式的答案...

    SELECT rn
         , field
         , SUBSTR( ','||field||','
                 , INSTR( ','||field||',', ',', 1, rn ) + 1
                 ,   INSTR( ','||field||',', ',', 1, rn+1 )
                   - INSTR( ','||field||',', ',', 1, rn )
                   - 1
                 ) separated_field
      FROM ( SELECT LEVEL rn FROM dual CONNECT BY LEVEL <= 40 ) -- Length of column
         , ( SELECT '6,7,99.3334' field FROM dual ) -- Source column
     WHERE rn <= (   LENGTH( field ) 
                   - LENGTH( REPLACE( field, ',', NULL ) ) 
                 ) + 1 -- Number of Commas plus one
    

    【讨论】:

      【解决方案3】:

      这是一个将 CSV 列拆分为多行的视图:

      CREATE OR REPLACE VIEW your_view AS
      SELECT tt.ID, SUBSTR(value, sp, ep-sp) split, other_col1, other_col2...
        FROM (SELECT id, value
                   , INSTR(','||value, ',', 1, L) sp  -- 1st posn of substr at this level
                   , INSTR(value||',', ',', 1, L) ep  -- posn of delimiter at this level
                FROM tt JOIN (SELECT LEVEL L FROM dual CONNECT BY LEVEL < 20) q -- 20 is max #substrings
                          ON LENGTH(value)-LENGTH(REPLACE(value,','))+1 >= L 
      ) qq JOIN tt on qq.id = tt.id;
      

      其中 tt 是您的桌子。

      适用于大于 1 或 null 的 csv 值。 CONNECT BY LEVEL

      举例说明:

          SQL> CREATE TABLE tt (ID INTEGER, c VARCHAR2(20), othercol VARCHAR2(20));
      
          Table created
          SQL> INSERT INTO tt VALUES (1, 'a,b,c', 'val1');
      
          1 row inserted
          SQL> INSERT INTO tt VALUES (2, 'd,e,f,g', 'val2');
      
          1 row inserted
          SQL> INSERT INTO tt VALUES (3, 'a,f', 'val3');
      
          1 row inserted
          SQL> INSERT INTO tt VALUES (4,'aa,bbb,cccc', 'val4');
      
          1 row inserted
          SQL> CREATE OR REPLACE VIEW myview AS
            2  SELECT tt.ID, SUBSTR(c, sp, ep-sp+1) splitval, othercol
            3    FROM (SELECT ID
            4               , INSTR(','||c,',',1,L) sp, INSTR(c||',',',',1,L)-1 ep
            5            FROM tt JOIN (SELECT LEVEL L FROM dual CONNECT BY LEVEL < 20) q
            6                      ON LENGTH(c)-LENGTH(REPLACE(c,','))+1 >= L
            7  ) q JOIN tt ON q.id =tt.id;
      
          View created
          SQL> select * from myview order by 1,2;
      
                                           ID SPLITVAL             OTHERCOL
      --------------------------------------- -------------------- --------------------
                                            1 a                    val1
                                            1 b                    val1
                                            1 c                    val1
                                            2 d                    val2
                                            2 e                    val2
                                            2 f                    val2
                                            2 g                    val2
                                            3 a                    val3
                                            3 f                    val3
                                            4 aa                   val4
                                            4 bbb                  val4
                                            4 cccc                 val4
      
      12 rows selected
      
      SQL> 
      

      【讨论】:

        【解决方案4】:

        这是另一种方法。这会将您的字符串解析为 PL/SQL 表。

        首先创建一个自定义类型,它是一个数字数组:

        CREATE OR REPLACE TYPE number_tab AS TABLE OF NUMBER;
        

        然后创建一个函数,它将逗号分隔的值列表转换为您的数组类型的实例:

        CREATE OR REPLACE FUNCTION csv_to_number_tab(p_string IN VARCHAR2)
            RETURN number_tab AS
            l_string       LONG DEFAULT p_string || ',';
            l_data         number_tab := number_tab();
            n              NUMBER;
        BEGIN
            LOOP
                EXIT WHEN l_string IS NULL;
                n := INSTR(l_string, ',');
                l_data.EXTEND;
                l_data(l_data.COUNT) := TO_NUMBER(LTRIM(RTRIM(SUBSTR(l_string, 1, n - 1))));
                l_string := SUBSTR(l_string, n + 1);
            END LOOP;
        
            RETURN l_data;
        END;
        

        这是一个展示用法的匿名块:

        DECLARE
            nt   number_tab := number_tab();
            i    NUMBER := 0;
        BEGIN
            nt  := csv_to_number_tab('1,2.3, 456.7, 89.1234,567890.12345');
        
            FOR i IN 1 .. nt.COUNT LOOP
                DBMS_OUTPUT.put_line(i || ' : ' || nt(i));
            END LOOP;
        END;
        

        请注意,一些值之间有空格,但其他值之间没有空格;该函数以任何方式处理它。

        【讨论】:

          【解决方案5】:

          您还没有说是否需要列或行中的项目。使用 xml 的行解决方案非常简单:http://pbarut.blogspot.com/2006/10/binding-list-variable.html

          基本上,您将字符串转换为 xml 文档,然后将值提取出来。

          【讨论】:

            猜你喜欢
            • 2017-07-04
            • 2015-04-01
            • 1970-01-01
            • 1970-01-01
            • 2015-03-25
            • 1970-01-01
            • 1970-01-01
            • 2015-10-06
            相关资源
            最近更新 更多