2015-09-13 1 views
-1

У меня есть таблица say A, и у нее есть только один столбец DATA.sql-запрос для разделения столбцов по двум атрибутам

DATA 
----- 
x=1;y=2;z=3 
x=4;y=5;z=6 
x=14;y=15;z=16;a=25 

Я хочу, чтобы результат, как показано ниже:

x   y   z  a 
-------------------------------- 
1   2   3  0 
4   5   6  0 
14  15   16  25 

Я использую жаба для обработки запросов.

+0

oracle версия? 10+? – Utsav

+0

@Utsav yes correct –

+0

Есть ли всегда только 3 значения? –

ответ

2

Протестировано в 12c. Сначала я разделяю данные на ';' а затем «=».

 with dat (data) as 
      (
      select 'x=1;y=2;z=3' from dual union 
      select 'x=4;y=5;z=6' from dual 
     ) 
      select 
      REGEXP_SUBSTR(REGEXP_SUBSTR(data,'[^;]+',1,1),'[^=]+',1,2) as x, 
      REGEXP_SUBSTR(REGEXP_SUBSTR(data,'[^;]+',1,2),'[^=]+',1,2) as y, 
      REGEXP_SUBSTR(REGEXP_SUBSTR(data,'[^;]+',1,3),'[^=]+',1,2) as z 
      from dat 

Выход

  X Y Z 
      1 2 3 
      4 5 6 
+0

Perfect..Thanks много. –

+0

Вы должны использовать NVL, поскольку OP хочет нуль в случае значений NULL. –

+0

Да. Но это было не в оригинальном посте. Anyways OP может изменить его в соответствии с его удобством. Спасибо за подсказку и примеры instr и substr. Всегда хорошо учиться чему-то. – Utsav

1

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

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

Если шаблон фиксировано, то вы могли бы использовать SUBSTR.

SQL> WITH DATA(str) AS(
    2 SELECT 'x=1;y=2;z=3' FROM dual UNION ALL 
    3 SELECT 'x=4;y=5;z=6' FROM dual 
    4 ) 
    5 SELECT substr(str, 3, 1) a, 
    6   substr(str, 7, 1) b, 
    7   substr(str, 11, 1) c 
    8 FROM DATA; 

A B C 
- - - 
1 2 3 
4 5 6 

SQL> 

Обновление

Если шаблон не является фиксированным, а затем использовать SUBSTR и Instr.

SQL> WITH DATA(str) AS 
    2 (SELECT 'x=1;y=2;z=3' FROM dual 
    3 UNION ALL 
    4 SELECT 'x=4;y=5;z=6' FROM dual 
    5 UNION ALL 
    6 SELECT 'x=14;y=15;z=16;A=25' FROM dual 
    7 ) 
    8 SELECT NVL(SUBSTR(str 
    9 ||';', instr(str 
10 ||';', '=', 1, 1) +1, instr(str 
11 ||';', ';', 1, 1) - instr(str 
12 ||';', '=', 1, 1) -1), '0') a, 
13 NVL(SUBSTR(str 
14 ||';', instr(str 
15 ||';', '=', 1, 2) +1, instr(str 
16 ||';', ';', 1, 2) - instr(str 
17 ||';', '=', 1, 2) -1), '0') b, 
18 NVL(SUBSTR(str 
19 ||';', instr(str 
20 ||';', '=', 1, 3) +1, instr(str 
21 ||';', ';', 1, 3) - instr(str 
22 ||';', '=', 1, 3) -1), '0') c, 
23 NVL(SUBSTR(str 
24 ||';', instr(str 
25 ||';', '=', 1, 4) +1, instr(str 
26 ||';', ';', 1, 4) - instr(str 
27 ||';', '=', 1, 4) -1), '0') d 
28 FROM DATA; 

A B C D 
- - - - 
1 2 3 0 
4 5 6 0 
1 1 1 2 
4 5 6 5 

Вы можете использовать регулярные выражения, который будет выглядеть более короткий код, однако, простой SUBTR и INSTR будет быстрее, чем регулярные выражения.

+0

Я не могу нормализовать этот столбец, потому что столбец динамический, и это не значит, что x = 1 придет, также может случиться так, что данные будут выглядеть следующим образом: x = new_data; y = good; z = well done. Поэтому я не могу use substr –

+0

Выглядит элегантно, но он сломается, если мы получим более 1-значного числа. Но для данных сценариев это прекрасно. – Utsav

+1

@AnkurVerma Нет проблем, см. Обновление. Используйте SUBSTR и INSTR для динамического извлечения данных. Это будет быстрее, чем регулярное выражение. –

1

Два решения, которые не зависят от данных, находящихся в заданном порядке:

SQL Fiddle

Oracle 11g R2 Настройка схемы:

CREATE TABLE A (DATA) AS 
      SELECT 'x=1;y=2;z=3' FROM DUAL 
UNION ALL SELECT 'y=5;z=6;x=4' FROM DUAL 
UNION ALL SELECT 'x=14;y=15;z=16;a=25' FROM DUAL 
UNION ALL SELECT 'y=9;a=4' FROM DUAL 

Запрос 1:

SELECT REGEXP_SUBSTR(DATA, 'x=(\d+)', 1, 1, 'i', 1) AS X, 
     REGEXP_SUBSTR(DATA, 'y=(\d+)', 1, 1, 'i', 1) AS Y, 
     REGEXP_SUBSTR(DATA, 'z=(\d+)', 1, 1, 'i', 1) AS Z, 
     REGEXP_SUBSTR(DATA, 'a=(\d+)', 1, 1, 'i', 1) AS A 
FROM A 

Results:

|  X | Y |  Z |  A | 
|--------|----|--------|--------| 
|  1 | 2 |  3 | (null) | 
|  4 | 5 |  6 | (null) | 
|  14 | 15 |  16 |  25 | 
| (null) | 9 | (null) |  4 | 

Запрос 2:

WITH POSITIONS AS (
    SELECT DATA, 
     INSTR(DATA, 'x=') AS X, 
     INSTR(DATA, ';', INSTR(DATA, 'x=')) AS X_SEP, 
     INSTR(DATA, 'y=') AS Y, 
     INSTR(DATA, ';', INSTR(DATA, 'y=')) AS Y_SEP, 
     INSTR(DATA, 'z=') AS Z, 
     INSTR(DATA, ';', INSTR(DATA, 'z=')) AS Z_SEP, 
     INSTR(DATA, 'a=') AS A, 
     INSTR(DATA, ';', INSTR(DATA, 'a=')) AS A_SEP 
    FROM A 
) 
SELECT CASE 
      WHEN X = 0  THEN NULL 
      WHEN X_SEP = 0 THEN TO_NUMBER(SUBSTR(DATA, X+2)) 
         ELSE TO_NUMBER(SUBSTR(DATA, X+2, X_SEP-X-2)) 
      END 
      AS X, 
     CASE 
      WHEN Y = 0  THEN NULL 
      WHEN Y_SEP = 0 THEN TO_NUMBER(SUBSTR(DATA, Y+2)) 
         ELSE TO_NUMBER(SUBSTR(DATA, Y+2, Y_SEP-Y-2)) 
      END 
      AS Y, 
     CASE 
      WHEN Z = 0  THEN NULL 
      WHEN Z_SEP = 0 THEN TO_NUMBER(SUBSTR(DATA, Z+2)) 
         ELSE TO_NUMBER(SUBSTR(DATA, Z+2, Z_SEP-Z-2)) 
      END 
      AS Z, 
     CASE 
      WHEN A = 0  THEN NULL 
      WHEN A_SEP = 0 THEN TO_NUMBER(SUBSTR(DATA, A+2)) 
         ELSE TO_NUMBER(SUBSTR(DATA, A+2, A_SEP-A-2)) 
      END 
      AS A 
FROM POSITIONS 

Results

|  X | Y |  Z |  A | 
|--------|----|--------|--------| 
|  1 | 2 |  3 | (null) | 
|  4 | 5 |  6 | (null) | 
|  14 | 15 |  16 |  25 | 
| (null) | 9 | (null) |  4 |