Разделенные запятыми значения в Oracle - PullRequest
2 голосов
/ 13 апреля 2010

У меня есть столбец со значениями, разделенными запятыми, например 6,7,99.3334.

Мне нужно написать процедуру PL SQL, которая даст мне эти значения отдельно. Длина столбца 40.

Может ли кто-нибудь помочь мне с этим?

Ответы [ 5 ]

2 голосов
/ 13 апреля 2010

Что-то вроде этого может быть?

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
;
1 голос
/ 08 июня 2011

Вот представление, которое разделит столбец 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 - ваш стол.

Работает для значений CSV длиннее 1 или ноль. CONNECT BY LEVEL <20 произвольно, с учетом вашей ситуации. </p>

Для иллюстрации:

    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> 
1 голос
/ 13 апреля 2010

Для ответа без регулярных выражений ...

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
0 голосов
/ 18 апреля 2010

Вы не сказали, хотите ли вы элементы в столбцах или строках. Решение строки довольно просто с использованием xml: http://pbarut.blogspot.com/2006/10/binding-list-variable.html

По сути, вы конвертируете строку в документ XML, а затем извлекаете значения.

0 голосов
/ 14 апреля 2010

Вот другой подход. Это разбирает вашу строку в таблицу 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;

Обратите внимание, что между одними значениями есть пробелы, но нет других; функция обрабатывает это в любом случае.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...