2010-05-07 6 views
1

Я опытный программист, но относительно новый для SQL. Мы используем Oracle 10 и 11. У меня есть система с использованием SQL, которая объединяет фактические строки с виртуальными строками (например, «SELECT 1 from DUAL»), которые делают союзы и пересекаются по мере необходимости, что все, кажется, работает.SQL-манипуляция строк для возврата нескольких строк

Моя проблема в том, что мне нужно объединить эту систему, которая ожидает строки данных, с новыми данными, которые будут иметь данные в (например, для упрощения) строках с разделителями-запятыми.

Поэтому я считаю, что мне нужно преобразовать строку типа «5,6,7,8» в 4 строки по одному столбцу, причем «5» в первой строке «6» в второй и т. д. На других языках я бы разделил запятую как разделитель. Конечно, данные не всегда будут содержать 4 записи.

Есть второй вопрос, но я попрошу его отдельно. Но я подозреваю, что это упростит ситуацию, если это возможно, если решение выше можно использовать в качестве таблицы в другом выражении SQL (т. Е. Работать с моей существующей системой). Спасибо за любую помощь.

+1

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

ответ

1

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

Если вы абсолютно должны сделать это в SQL, эта статья покажет вам, как сделать это:

http://www.oracle.com/technology/oramag/code/tips2007/070907.html

2

Это выглядит некрасиво, но это работает:

select r 
     ,substr(','||csv||',', 
       instr(','||csv||',',',',1,r)+1, 
       instr(','||csv||',',',',1,r+1)-instr(','||csv||',',',',1,r)-1) v 
from (select '5,6,7a,8b,,bob' csv from dual) 
     ,(select rownum r from dual connect by level <= 4000) 
where instr(csv||',',',',1,r) > 0; 

 
R V 
= = 
1 5 
2 6 
3 7a 
4 8b 
5 
6 bob 

1

Для использования SQL вы можете сделать следующее ...

CREATE OR REPLACE TYPE tab_varchar2 AS TABLE OF VARCHAR2(4000); 
/

CREATE OR REPLACE FUNCTION string_to_rows 
    (pv_string IN VARCHAR2 
    , pv_delimiter IN VARCHAR2 DEFAULT '_' 
    ) 
    RETURN tab_varchar2 
    PIPELINED 
AS 
    lv_string VARCHAR2(32767) DEFAULT pv_string || pv_delimiter; 
    lv_num PLS_INTEGER; 
BEGIN 
    LOOP 
     lv_num := INSTR(lv_string, pv_delimiter); 
     EXIT WHEN (NVL(lv_num, 0) = 0); 

     PIPE ROW(LTRIM(RTRIM(SUBSTR(lv_string, 1, lv_num - 1)))); 

     lv_string := LTRIM(SUBSTR(lv_string, lv_num + 1)); 

    END LOOP; 

    RETURN; 
END; 
/

Затем вы можете запустить что-то вроде этого ...

SELECT c.owner, c.table_name, c.column_name, c.data_type 
    , t.column_value column_token 
    FROM dba_tab_columns c 
    , TABLE(string_to_rows(c.column_name)) t 
WHERE c.owner = 'SYS' 
    AND c.table_name = 'DBA_INDEXES' 
    AND c.column_name = 'AVG_LEAF_BLOCKS_PER_KEY' 

Что бы вернуть это ...

Row# OWNER TABLE_NAME COLUMN_NAME    DATA_TYPE COLUMN_TOKEN 
---- ----- ----------- ----------------------- --------- ------------ 
1 SYS DBA_INDEXES AVG_LEAF_BLOCKS_PER_KEY NUMBER AVG 
2 SYS DBA_INDEXES AVG_LEAF_BLOCKS_PER_KEY NUMBER LEAF 
3 SYS DBA_INDEXES AVG_LEAF_BLOCKS_PER_KEY NUMBER BLOCKS 
4 SYS DBA_INDEXES AVG_LEAF_BLOCKS_PER_KEY NUMBER PER 
5 SYS DBA_INDEXES AVG_LEAF_BLOCKS_PER_KEY NUMBER KEY 
Смежные вопросы