развернуть oracle полей таблицы линейно - PullRequest
1 голос
/ 04 мая 2020

У меня есть следующая таблица в oracle:

ID    field_1    field_2
1       1-5        1-5
1      20-30      55-65
2       1-8       10-17
2      66-72      80-86

Мне нужно преобразовать эту таблицу в следующий формат, где field_1 и field_2 должны совпадать линейно:

   ID   field_1  field_2
    1      1       1
    1      2       2
    1      3       3
    1      4       4
    1      5       5
    1      20      55
    1      21      56
    1      22      57
    1      23      58
    1      24      59
    1      25      60
    1      26      61
    1      27      62
    1      28      63
    1      29      64
    1      30      65
    2      1       10
    2      2       11
    2      3       12
    2      4       13
    2      5       14
    2      6       15
    2      7       16
    2      8       17
    2      66      80
    2      67      81
    2      68      82
    2      69      83
    2      70      84
    2      71      85
    2      72      86

Какой самый простой и быстрый способ выполнить это sh, зная, что исходная таблица содержит тысячи записей

Ответы [ 3 ]

1 голос
/ 04 мая 2020

Предложение lateral, используемое ниже, доступно с Oracle 12.1. Для более старых версий connect by иерархический запрос все еще, вероятно, самый быстрый, но его нужно будет написать с большей осторожностью (и он будет медленнее, чем использование connect by в боковом соединении) .

Конечно, большое допущение состоит в том, что входные данные всегда имеют номер number-da sh -number, и что разница между верхней и нижней границами одинакова в двух столбцах, для каждого ряда. Я даже не пытаюсь проверить это.

select t.id, l.field_1, l.field_2
from   mytable t, 
       lateral (select to_number(substr(field_1, 1, instr(field_1, '-') - 1))
                              + level - 1 as field_1,
                       to_number(substr(field_2, 1, instr(field_2, '-') - 1))
                              + level - 1 as field_2
                from   dual
                connect by level <= 
                   to_number(substr(field_1, instr(field_1, '-') + 1))
                 - to_number(substr(field_1, 1, instr(field_1, '-') - 1)) + 1
               ) l
;
1 голос
/ 04 мая 2020

Один вариант использует рекурсивный запрос. Начиная с 11gR2, Oracle поддерживает стандартные рекурсивные общие табличные выражения, поэтому вы можете сделать:

with cte(id, field_1, field_2, max_field_1, max_field_2) as (
    select 
        id, 
        to_number(regexp_substr(field_1, '^\d+')), 
        to_number(regexp_substr(field_2, '^\d+')),
        to_number(regexp_substr(field_1, '\d+$')), 
        to_number(regexp_substr(field_2, '\d+$'))
    from mytable
    union all
    select
        id,
        field_1 + 1,
        field_2 + 1,
        max_field_1,
        max_field_2
    from cte
    where field_1 < max_field_1
)
select id, field_1, field_2 from cte order by id, field_1   

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

Демонстрация на DB Fiddle :

ID | FIELD_1 | FIELD_2
-: | ------: | ------:
 1 |       1 |       1
 1 |       2 |       2
 1 |       3 |       3
 1 |       4 |       4
 1 |       5 |       5
 1 |      20 |      55
 1 |      21 |      56
 1 |      22 |      57
 1 |      23 |      58
 1 |      24 |      59
 1 |      25 |      60
 1 |      26 |      61
 1 |      27 |      62
 1 |      28 |      63
 1 |      29 |      64
 1 |      30 |      65
 2 |       1 |      10
 2 |       2 |      11
 2 |       3 |      12
 2 |       4 |      13
 2 |       5 |      14
 2 |       6 |      15
 2 |       7 |      16
 2 |       8 |      17
 2 |      66 |      80
 2 |      67 |      81
 2 |      68 |      82
 2 |      69 |      83
 2 |      70 |      84
 2 |      71 |      85
 2 |      72 |      86
0 голосов
/ 04 мая 2020

Вы можете использовать cross join с сгенерированными значениями следующим образом:

SELECT ID, 
       to_number(regexp_substr(field_1, '[0-9]+',1,1)) + column_value - 1 AS FIELD_1, 
       to_number(regexp_substr(field_2, '[0-9]+',1,1)) + column_value - 1 AS FIELD_2
  FROM your_table
cross join
     table(cast(multiset(select level from dual
                         connect by level <= 
                                 to_number(regexp_substr(field_1, '[0-9]+',1,2)) 
                                 - to_number(regexp_substr(field_1, '[0-9]+',1,1)) 
                                 + 1
                        ) as sys.odcinumberlist))
ORDER BY 1,2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...